From 9c60521d00aef3a2b304763a55b21f01dc2c9bd8 Mon Sep 17 00:00:00 2001 From: cir27 Date: Tue, 2 May 2017 16:41:40 +1200 Subject: [PATCH 01/32] Merge branch 'develop' of C:\Users\CJIRWIN\Documents\team-13 with conflicts. --- src/main/java/seng302/App.java | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/main/java/seng302/App.java b/src/main/java/seng302/App.java index 0637d2cc..39ca3e8a 100644 --- a/src/main/java/seng302/App.java +++ b/src/main/java/seng302/App.java @@ -5,6 +5,9 @@ import javafx.fxml.FXMLLoader; import javafx.scene.Parent; import javafx.scene.Scene; import javafx.stage.Stage; +import seng302.models.parsers.StreamParser; +import seng302.models.parsers.StreamReceiver; +import seng302.server.ServerThread; public class App extends Application { @@ -18,6 +21,28 @@ public class App extends Application } public static void main(String[] args) { + StreamReceiver sr; + + new ServerThread("Racevision Test Server"); + try { + Thread.sleep(2000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + +// if (args.length > 1){ +// sr = new StreamReceiver("localhost", 8085, "RaceStream"); +// } +// else{ + sr = new StreamReceiver("csse-s302staff.canterbury.ac.nz", 4941,"RaceStream"); +// sr = new StreamReceiver("livedata.americascup.com", 4941, "RaceStream"); +// sr = new StreamReceiver("localhost", 8085, "RaceStream"); +// } + + sr.start(); + StreamParser streamParser = new StreamParser("StreamParser"); + streamParser.start(); + launch(args); } } From 6d7697a0ebe51b358b0501edc694f1b789244d69 Mon Sep 17 00:00:00 2001 From: Peter Galloway Date: Wed, 10 May 2017 13:58:10 +1200 Subject: [PATCH 02/32] commented out the problematic buffering functionality #story[923] --- .../seng302/controllers/CanvasController.java | 41 ++++++++++--------- .../seng302/models/parsers/StreamParser.java | 24 +++++------ 2 files changed, 33 insertions(+), 32 deletions(-) diff --git a/src/main/java/seng302/controllers/CanvasController.java b/src/main/java/seng302/controllers/CanvasController.java index 8fc7ed54..21f89ca3 100644 --- a/src/main/java/seng302/controllers/CanvasController.java +++ b/src/main/java/seng302/controllers/CanvasController.java @@ -69,6 +69,7 @@ public class CanvasController { private int frameTimeIndex = 0; private boolean arrayFilled = false; private DecimalFormat decimalFormat2dp = new DecimalFormat("0.00"); + private double lastPacketTime = 0; public AnimationTimer timer; @@ -245,27 +246,27 @@ public class CanvasController { private void move(long id, RaceObject raceObject){ PriorityBlockingQueue movementQueue = StreamParser.boatPositions.get(id); if (movementQueue.size() > 0){ - BoatPositionPacket positionPacket = movementQueue.peek(); - - //this code adds a delay to reading from the movementQueue - //in case things being put into the movement queue are slightly - //out of order - int delayTime = 1000; - int loopTime = delayTime * 10; - long timeDiff = (System.currentTimeMillis()%loopTime - positionPacket.getTimeValid()%loopTime); - if (timeDiff < 0){ - timeDiff = loopTime + timeDiff; - } - if (timeDiff > delayTime) { - try { - positionPacket = movementQueue.take(); - Point2D p2d = latLonToXY(positionPacket.getLat(), positionPacket.getLon()); - double heading = 360.0 / 0xffff * positionPacket.getHeading(); - raceObject.setDestination(p2d.getX(), p2d.getY(), heading, positionPacket.getGroundSpeed(), (int) id); - } catch (InterruptedException e){ - e.printStackTrace(); - } +// BoatPositionPacket positionPacket = movementQueue.peek(); +// +// //this code adds a delay to reading from the movementQueue +// //in case things being put into the movement queue are slightly +// //out of order +// int delayTime = 1000; +// int loopTime = delayTime * 10; +// long timeDiff = (System.currentTimeMillis()%loopTime - positionPacket.getTimeValid()%loopTime); +// if (timeDiff < 0){ +// timeDiff = loopTime + timeDiff; +// } +// if (timeDiff > delayTime) { + try { + BoatPositionPacket positionPacket = movementQueue.take(); + Point2D p2d = latLonToXY(positionPacket.getLat(), positionPacket.getLon()); + double heading = 360.0 / 0xffff * positionPacket.getHeading(); + raceObject.setDestination(p2d.getX(), p2d.getY(), heading, positionPacket.getGroundSpeed(), (int) id); + } catch (InterruptedException e){ + e.printStackTrace(); } +// } } } diff --git a/src/main/java/seng302/models/parsers/StreamParser.java b/src/main/java/seng302/models/parsers/StreamParser.java index deea3184..dce7e172 100644 --- a/src/main/java/seng302/models/parsers/StreamParser.java +++ b/src/main/java/seng302/models/parsers/StreamParser.java @@ -69,21 +69,21 @@ public class StreamParser extends Thread{ StreamPacket packet = StreamReceiver.packetBuffer.peek(); //this code adds a delay to reading from the packetBuffer so //out of order packets have time to order themselves in the queue - int delayTime = 1000; - int loopTime = delayTime * 10; - long transitTime = (System.currentTimeMillis()%loopTime - packet.getTimeStamp()%loopTime); - if (transitTime < 0){ - transitTime = loopTime + transitTime; - } - if (transitTime < delayTime) { - long sleepTime = delayTime - (transitTime); - Thread.sleep(sleepTime); - } +// int delayTime = 1000; +// int loopTime = delayTime * 10; +// long transitTime = (System.currentTimeMillis()%loopTime - packet.getTimeStamp()%loopTime); +// if (transitTime < 0){ +// transitTime = loopTime + transitTime; +// } +// if (transitTime < delayTime) { +// long sleepTime = delayTime - (transitTime); +// Thread.sleep(sleepTime); +// } packet = StreamReceiver.packetBuffer.take(); parsePacket(packet); - Thread.sleep(1); +// Thread.sleep(1); while (StreamReceiver.packetBuffer.peek() == null) { - Thread.sleep(1); +// Thread.sleep(1); } } } catch (Exception e){ From 03ca60f2e123002a6bb5cdfde250ecd7d9e9579b Mon Sep 17 00:00:00 2001 From: Peter Galloway Date: Sun, 14 May 2017 20:12:35 +1200 Subject: [PATCH 03/32] deleted a whole bunch of legacy code, primarily the old controllers and old parsers #story[923] --- src/main/java/seng302/App.java | 2 +- .../seng302/controllers/CanvasController.java | 128 ++--------- .../java/seng302/controllers/Controller.java | 20 +- .../seng302/controllers/RaceController.java | 82 -------- .../controllers/RaceResultController.java | 37 ---- .../controllers/RaceViewController.java | 185 ---------------- src/main/java/seng302/models/Race.java | 198 ------------------ .../java/seng302/models/mark/MarkGroup.java | 4 +- .../seng302/models/parsers/ConfigParser.java | 78 ------- .../seng302/models/parsers/CourseParser.java | 145 ------------- .../seng302/models/parsers/FileParser.java | 54 ----- .../seng302/models/parsers/TeamsParser.java | 64 ------ .../seng302/models/parsers/XMLParser.java | 8 + src/main/resources/views/RaceView.fxml | 12 -- src/test/java/seng302/RaceTest.java | 41 ---- .../models/parsers/ConfigParserTest.java | 42 ---- .../models/parsers/CourseParserTest.java | 59 ------ 17 files changed, 36 insertions(+), 1123 deletions(-) delete mode 100644 src/main/java/seng302/controllers/RaceController.java delete mode 100644 src/main/java/seng302/controllers/RaceResultController.java delete mode 100644 src/main/java/seng302/models/Race.java delete mode 100644 src/main/java/seng302/models/parsers/ConfigParser.java delete mode 100644 src/main/java/seng302/models/parsers/CourseParser.java delete mode 100644 src/main/java/seng302/models/parsers/FileParser.java delete mode 100644 src/main/java/seng302/models/parsers/TeamsParser.java delete mode 100644 src/test/java/seng302/RaceTest.java delete mode 100644 src/test/java/seng302/models/parsers/ConfigParserTest.java delete mode 100644 src/test/java/seng302/models/parsers/CourseParserTest.java diff --git a/src/main/java/seng302/App.java b/src/main/java/seng302/App.java index 1a400afd..19a30595 100644 --- a/src/main/java/seng302/App.java +++ b/src/main/java/seng302/App.java @@ -62,7 +62,7 @@ public class App extends Application } //Change the StreamReceiver in this else block to change the default data source. else{ - sr = new StreamReceiver("localhost", 4949, "RaceStream"); + sr = new StreamReceiver("livedata.americascup.com", 4941, "RaceStream"); } sr.start(); diff --git a/src/main/java/seng302/controllers/CanvasController.java b/src/main/java/seng302/controllers/CanvasController.java index 21f89ca3..d477734d 100644 --- a/src/main/java/seng302/controllers/CanvasController.java +++ b/src/main/java/seng302/controllers/CanvasController.java @@ -59,7 +59,6 @@ public class CanvasController { private Mark maxLonPoint; private double referencePointX; private double referencePointY; - private double metersToPixels; private List raceObjects = new ArrayList<>(); private List raceMarks = new ArrayList<>(); @@ -179,57 +178,6 @@ public class CanvasController { gc.fillPolygon(xBoundaryPoints,yBoundaryPoints,yBoundaryPoints.length); } - - /** - * Adds the course marks to the canvas, taken from the XMl file - * - * NOTE: This is quite confusing as objects are grabbed from the XMLParser such as Mark and CompoundMark which are - * named the same as those in the model package but are, however not the same, so they do not have things such as - * a type and must be derived from the number of marks in a compound mark etc.. - */ - private void addCourseMarks() { - XMLParser.RaceXMLObject raceXMLObject = StreamParser.getXmlObject().getRaceXML(); - ArrayList compoundMarks = raceXMLObject.getCompoundMarks(); - RaceObject markGroup; - - for (CompoundMark compoundMark : compoundMarks) { - - //If the compound mark has 2 marks then its a gate mark - if (compoundMark.getMarks().size() == 2) { - CompoundMark.Mark mark1 = compoundMark.getMarks().get(0); - CompoundMark.Mark mark2 = compoundMark.getMarks().get(1); - SingleMark singleMark1 = new SingleMark(mark1.getMarkName(), mark1.getTargetLat(), mark1.getTargetLng(), mark1.getSourceID()); - SingleMark singleMark2 = new SingleMark(mark1.getMarkName(), mark2.getTargetLat(), mark2.getTargetLng(), mark2.getSourceID()); - GateMark thisGateMark = new GateMark(compoundMark.getcMarkName(), - (compoundMark.getMarkID().equals(1)) ? MarkType.OPEN_GATE : MarkType.CLOSED_GATE, - singleMark1, - singleMark2, - singleMark1.getLatitude(), - singleMark1.getLongitude()); - - markGroup = new MarkGroup(thisGateMark, - findScaledXY(thisGateMark.getSingleMark1()), - findScaledXY(thisGateMark.getSingleMark2())); - - raceObjects.add(markGroup); - raceMarks.add(thisGateMark); - - //Otherwise its a single mark - } else { - CompoundMark.Mark singleMark = compoundMark.getMarks().get(0); - Mark thisSingleMark = new SingleMark(singleMark.getMarkName(), - singleMark.getTargetLat(), - singleMark.getTargetLng(), - singleMark.getSourceID()); - - markGroup = new MarkGroup(thisSingleMark, findScaledXY(thisSingleMark)); - raceObjects.add(markGroup); - raceMarks.add(thisSingleMark); - - } - } - } - private void updateRaceObjects(){ for (RaceObject raceObject : raceObjects) { raceObject.updatePosition(1000 / 60); @@ -325,15 +273,15 @@ public class CanvasController { // Map timelineInfos = raceViewController.getTimelineInfos(); // List boats = raceViewController.getStartingBoats(); Map boats = StreamParser.getBoats(); - Double startingX = raceObjects.get(0).getLayoutX(); - Double startingY = raceObjects.get(0).getLayoutY(); +// Double startingX = raceObjects.get(0).getLayoutX(); +// Double startingY = raceObjects.get(0).getLayoutY(); Group boatAnnotations = new Group(); for (Yacht boat : boats.values()) { // for (Boat boat : boats) { boat.setColour(Colors.getColor()); BoatGroup boatGroup = new BoatGroup(boat, boat.getColour()); - boatGroup.moveTo(startingX, startingY, 0d); +// boatGroup.moveTo(startingX, startingY, 0d); //boatGroup.setStage(raceViewController.getStage()); raceObjects.add(boatGroup); boatAnnotations.getChildren().add(boatGroup.getLowPriorityAnnotations()); @@ -349,9 +297,8 @@ public class CanvasController { findMinMaxPoint(); double minLonToMaxLon = scaleRaceExtremities(); calculateReferencePointLocation(minLonToMaxLon); - givePointsXY(); + //givePointsXY(); addRaceBorder(); - findMetersToPixels(); } @@ -448,25 +395,25 @@ public class CanvasController { * Give all markers in the course an x,y location relative to a given reference with a known x,y location. Distances * are scaled according to the distanceScaleFactor variable. */ - private void givePointsXY() { - List allPoints = new ArrayList<>(raceViewController.getRace().getCourse()); - List processed = new ArrayList<>(); - RaceObject markGroup; - - for (Mark mark : allPoints) { - if (!processed.contains(mark)) { - if (mark.getMarkType() != MarkType.SINGLE_MARK) { - GateMark gateMark = (GateMark) mark; - markGroup = new MarkGroup(mark, findScaledXY(gateMark.getSingleMark1()), findScaledXY(gateMark.getSingleMark2())); - raceObjects.add(markGroup); - } else { - markGroup = new MarkGroup(mark, findScaledXY(mark)); - raceObjects.add(markGroup); - } - processed.add(mark); - } - } - } +// private void givePointsXY() { +// List allPoints = new ArrayList<>(raceViewController.getRace().getCourse()); +// List processed = new ArrayList<>(); +// RaceObject markGroup; +// +// for (Mark mark : allPoints) { +// if (!processed.contains(mark)) { +// if (mark.getMarkType() != MarkType.SINGLE_MARK) { +// GateMark gateMark = (GateMark) mark; +// markGroup = new MarkGroup(mark, findScaledXY(gateMark.getSingleMark1()), findScaledXY(gateMark.getSingleMark2())); +// raceObjects.add(markGroup); +// } else { +// markGroup = new MarkGroup(mark, findScaledXY(mark)); +// raceObjects.add(markGroup); +// } +// processed.add(mark); +// } +// } +// } private Point2D findScaledXY (Mark unscaled) { return findScaledXY (minLatPoint.getLatitude(), minLatPoint.getLongitude(), @@ -501,35 +448,6 @@ public class CanvasController { } - - /** - * Find the number of meters per pixel. - */ - private void findMetersToPixels () { - Double angularDistance; - Double angle; - Double straightLineDistance; - if (scaleDirection == ScaleDirection.HORIZONTAL) { - angularDistance = Mark.calculateDistance(minLonPoint, maxLonPoint); - angle = Mark.calculateHeadingRad(minLonPoint, maxLonPoint); - if (angle > Math.PI / 2) { - straightLineDistance = Math.cos(angle - Math.PI) * angularDistance; - } else { - straightLineDistance = Math.cos(angle) * angularDistance; - } - metersToPixels = (CANVAS_WIDTH - RHS_BUFFER - LHS_BUFFER) / straightLineDistance; - } else { - angularDistance = Mark.calculateDistance(minLatPoint, maxLatPoint); - angle = Mark.calculateHeadingRad(minLatPoint, maxLatPoint); - if (angle < Math.PI / 2) { - straightLineDistance = Math.cos(angle) * angularDistance; - } else { - straightLineDistance = Math.cos(-angle + Math.PI * 2) * angularDistance; - } - metersToPixels = (CANVAS_HEIGHT - TOP_BUFFER - BOT_BUFFER) / straightLineDistance; - } - } - private Point2D latLonToXY (double latitude, double longitude) { return findScaledXY(minLatPoint.getLatitude(), minLatPoint.getLongitude(), latitude, longitude); } diff --git a/src/main/java/seng302/controllers/Controller.java b/src/main/java/seng302/controllers/Controller.java index 7d45d39b..eeae57cc 100644 --- a/src/main/java/seng302/controllers/Controller.java +++ b/src/main/java/seng302/controllers/Controller.java @@ -28,7 +28,7 @@ import java.util.ResourceBundle; import java.util.Timer; import java.util.TimerTask; -public class Controller implements Initializable { +public class Controller { @FXML private AnchorPane contentPane; @FXML @@ -66,13 +66,6 @@ public class Controller implements Initializable { } } - @Override - public void initialize(URL location, ResourceBundle resources) { - //DateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss"); - //format.setTimeZone(TimeZone.getTimeZone("GMT-8")); - //realTime.setText(format.format(new Date())); - } - /** * Running a timer to update the livestream status on welcome screen. Update interval is 1 second. */ @@ -147,18 +140,9 @@ public class Controller implements Initializable { posCol.setCellValueFactory( new PropertyValueFactory<>("position") ); -// if (StreamParser.isRaceStarted()) { data.addAll(StreamParser.getBoatsPos().values()); -// } else { -// for (Yacht boat : StreamParser.getBoats().values()) { -// boat.setPosition("-"); -// data.add(boat); -// } -// } + teamList.refresh(); -// posCol.setSortType(TableColumn.SortType.ASCENDING); -// teamList.getSortOrder().add(posCol); -// posCol.setSortable(false); } } diff --git a/src/main/java/seng302/controllers/RaceController.java b/src/main/java/seng302/controllers/RaceController.java deleted file mode 100644 index d0ea0d42..00000000 --- a/src/main/java/seng302/controllers/RaceController.java +++ /dev/null @@ -1,82 +0,0 @@ -package seng302.controllers; - -import seng302.models.Race; -import seng302.models.Yacht; -import seng302.models.parsers.ConfigParser; -import seng302.models.parsers.CourseParser; -import seng302.models.parsers.StreamParser; - -import java.lang.reflect.Array; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Map; -import java.util.Random; - -/** - * Created by zyt10 on 17/03/17. - * run before CanvasController to initialize race events - * the CanvasController then uses the event data to make the animations - */ -public class RaceController { - Race race = null; - - public void initializeRace() { - String raceConfigFile = "/config/config.xml"; - String teamsConfigFile = "/config/teams.xml"; - - try { - race = createRace(raceConfigFile, teamsConfigFile); - } catch (Exception e) { - System.out.println("There was an error creating the race."); - } - - if (race != null) { - race.startRace(); - } else { - System.out.println("There was an error creating the race. Exiting."); - } - } - - public Race createRace(String configFile, String teamsConfigFile) throws Exception { - Race race = new Race(); -// StreamParser.xmlObject - // Read team names from file -// TeamsParser tp = new TeamsParser(teamsConfigFile); - - // Read course from file -// ConfigParser config = new ConfigParser(configFile); - - ArrayList boatNames = new ArrayList<>(); -// ArrayList teams = tp.getBoats(); - Map teams = StreamParser.getBoatsPos(); - - //get race size - int numberOfBoats = teams.size(); - - //get time scale -// double timeScale = config.getTimeScale(); -// race.setTimeScale(timeScale); - - for (Yacht boat : teams.values()) { - boatNames.add(boat.getBoatName()); - race.addBoat(boat); - } - - // Shuffle team names - long seed = System.nanoTime(); - Collections.shuffle(boatNames, new Random(seed)); - - if (numberOfBoats > Array.getLength(boatNames.toArray())) { - return null; - } - - CourseParser course = new CourseParser("/config/course.xml"); - race.addCourse(course.getCourse()); - - return race; - } - - public Race getRace() { - return race; - } -} diff --git a/src/main/java/seng302/controllers/RaceResultController.java b/src/main/java/seng302/controllers/RaceResultController.java deleted file mode 100644 index bff697ed..00000000 --- a/src/main/java/seng302/controllers/RaceResultController.java +++ /dev/null @@ -1,37 +0,0 @@ -package seng302.controllers; - -import javafx.fxml.FXML; -import javafx.fxml.Initializable; -import javafx.scene.layout.AnchorPane; -import javafx.scene.layout.VBox; -import javafx.scene.text.Text; -import seng302.models.Race; - -import java.net.URL; -import java.util.ResourceBundle; - -/** - * Created by ptg19 on 20/03/17. - */ -public class RaceResultController implements Initializable{ - @FXML private AnchorPane window; - @FXML private VBox resultsVBox; - private Race race; - - RaceResultController(Race race){ - this.race = race; - } - - @Override - public void initialize(URL location, ResourceBundle resources) { - int boatPosition = this.race.getFinishedBoats().length; - - for (int i = this.race.getFinishedBoats().length - 1; i >= 0; i--){ - resultsVBox.getChildren().add(0, new Text(boatPosition + ": " + this.race.getFinishedBoats()[i].getBoatName())); - boatPosition--; - } - - - - } -} diff --git a/src/main/java/seng302/controllers/RaceViewController.java b/src/main/java/seng302/controllers/RaceViewController.java index a4cc2ece..f8eed705 100644 --- a/src/main/java/seng302/controllers/RaceViewController.java +++ b/src/main/java/seng302/controllers/RaceViewController.java @@ -1,12 +1,9 @@ package seng302.controllers; -import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer; -import javafx.animation.Animation; import javafx.animation.KeyFrame; import javafx.animation.Timeline; import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; -import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.fxml.FXMLLoader; import javafx.scene.control.CheckBox; @@ -16,11 +13,9 @@ import javafx.scene.layout.Pane; import javafx.scene.layout.VBox; import javafx.scene.paint.Color; import javafx.scene.text.Text; -import javafx.stage.Stage; import javafx.util.Duration; import javafx.util.StringConverter; import seng302.models.*; -import seng302.models.parsers.ConfigParser; import seng302.models.parsers.StreamParser; import java.io.IOException; @@ -48,36 +43,16 @@ public class RaceViewController extends Thread{ private ArrayList startingBoats = new ArrayList<>(); private boolean displayFps; private Timeline timerTimeline; - private Map timelineInfos = new HashMap<>(); private ArrayList boatOrder = new ArrayList<>(); - private Race race; - private Stage stage; public void initialize() { - RaceController raceController = new RaceController(); - raceController.initializeRace(); - race = raceController.getRace(); - for (Yacht boat : race.getBoats()) { - startingBoats.add(boat); - } -// try{ -// initializeTimelines(); -// } -// catch (Exception e){ -// e.printStackTrace(); -// } - includedCanvasController.setup(this); includedCanvasController.initializeCanvas(); initializeTimer(); initializeSettings(); initialiseWindDirection(); initialisePositionVBox(); - //set wind direction!!!!!!! can't find another place to put my code --haoming -// double windDirection = new ConfigParser("/config/config.xml").getWindDirection(); -// windDirectionText.setText(String.format("%.1f°", windDirection)); -// windArrowText.setRotate(windDirection); includedCanvasController.timer.start(); } @@ -163,7 +138,6 @@ public class RaceViewController extends Thread{ } private void initialisePositionVBox() { - Timeline posVBoxTimeline = new Timeline(); posVBoxTimeline.setCycleCount(Timeline.INDEFINITE); posVBoxTimeline.getKeyFrames().add( @@ -173,143 +147,12 @@ public class RaceViewController extends Thread{ }) ); posVBoxTimeline.playFromStart(); - - } - - /** - * Generates time line for each boat, and stores time time into timelineInfos hash map - */ - private void initializeTimelines() { - HashMap boat_events = race.getEvents(); - for (Yacht boat : boat_events.keySet()) { - startingBoats.add(boat); -// // x, y are the real time coordinates -// DoubleProperty x = new SimpleDoubleProperty(); -// DoubleProperty y = new SimpleDoubleProperty(); -// -// List keyFrames = new ArrayList<>(); -// List events = boat_events.get(boat); -// -// // iterates all events and convert each event to keyFrame, then add them into a list -// for (Event event : events) { -// if (event.getIsFinishingEvent()) { -// keyFrames.add( -// new KeyFrame(Duration.seconds(event.getTime()), -// onFinished -> {race.setBoatFinished(boat); handleEvent(event);}, -// new KeyValue(x, event.getThisMark().getLatitude()), -// new KeyValue(y, event.getThisMark().getLongitude()) -// ) -// ); -// } else { -// keyFrames.add( -// new KeyFrame(Duration.seconds(event.getTime()), -// onFinished ->{ -// handleEvent(event); -// boat.setHeading(event.getBoatHeading()); -// }, -// new KeyValue(x, event.getThisMark().getLatitude()), -// new KeyValue(y, event.getThisMark().getLongitude()) -// ) -// ); -// } -// } -// timelineInfos.put(boat, new TimelineInfo(new Timeline(keyFrames.toArray(new KeyFrame[keyFrames.size()])), x, y)); - } - setRaceDuration(); - } - - private void setRaceDuration(){ - Double maxDuration = 0.0; - Timeline maxTimeline = null; - - for (TimelineInfo timelineInfo : timelineInfos.values()) { - - Timeline timeline = timelineInfo.getTimeline(); - if (timeline.getTotalDuration().toMillis() >= maxDuration) { - maxDuration = timeline.getTotalDuration().toMillis(); - maxTimeline = timeline; - } - - // Timelines are paused by default - timeline.play(); - timeline.pause(); - } - - maxTimeline.setOnFinished(event -> { - race.setRaceFinished(); - loadRaceResultView(); - }); - } - - /** - * Play each boats timerTimeline - */ - public void playTimelines(){ - for (TimelineInfo timelineInfo : timelineInfos.values()){ - Timeline timeline = timelineInfo.getTimeline(); - - if (timeline.getStatus() == Animation.Status.PAUSED){ - timeline.play(); - } - } - } - - /** - * Pause each boats timerTimeline - */ - public void pauseTimelines(){ - for (TimelineInfo timelineInfo : timelineInfos.values()){ - Timeline timeline = timelineInfo.getTimeline(); - - if (timeline.getStatus() == Animation.Status.RUNNING){ - timeline.pause(); - } - } - } - - /** - * Display the list of boats in the order they finished the race - */ - private void loadRaceResultView() { - FXMLLoader loader = new FXMLLoader(getClass().getResource("/views/FinishView.fxml")); - loader.setController(new RaceResultController(race)); - - try { - contentAnchorPane.getChildren().removeAll(); - contentAnchorPane.getChildren().clear(); - contentAnchorPane.getChildren().addAll((Pane) loader.load()); - - } catch (javafx.fxml.LoadException e) { - System.err.println(e.getCause()); - } catch (IOException e) { - System.err.println(e); - } - } - - public void handleEvent(Event event) { - Yacht boat = event.getBoat(); - boatOrder.remove(boat); - boat.setMarkLastPast(event.getMarkPosInRace()); - boatOrder.add(boat); - boatOrder.sort(new Comparator() { - @Override - public int compare(Yacht b1, Yacht b2) { - return b2.getMarkLastPast() - b1.getMarkLastPast(); - } - }); - showOrder(); } private void showOrder() { positionVbox.getChildren().clear(); positionVbox.getChildren().removeAll(); - -// for (Boat boat : boatOrder) { -// positionVbox.getChildren().add(new Text(boat.getShortName() + " " + boat.getSpeedInKnots() + " Knots")); -// } - for (Yacht boat : StreamParser.getBoatsPos().values()) { -// System.out.println(boat.getBoatStatus()); if (boat.getBoatStatus() == 3) { // 3 is finish status positionVbox.getChildren().add(new Text(boat.getPosition() + ". " + boat.getShortName() + " (Finished)")); @@ -354,30 +197,10 @@ public class RaceViewController extends Thread{ return timerString; } - public void stopTimer() { - timerTimeline.stop(); - } - public void startTimer() { - timerTimeline.play(); - } - public boolean isDisplayFps() { return displayFps; } - public Race getRace() { - return race; - } - - public Map getTimelineInfos() { - return timelineInfos; - } - - public ArrayList getStartingBoats(){ - return startingBoats; - } - - private void setAnnotations(Integer annotationLevel) { switch (annotationLevel) { case 0: @@ -426,12 +249,4 @@ public class RaceViewController extends Thread{ break; } } - - void setStage (Stage stage) { - this.stage = stage; - } - - Stage getStage () { - return stage; - } } \ No newline at end of file diff --git a/src/main/java/seng302/models/Race.java b/src/main/java/seng302/models/Race.java deleted file mode 100644 index e78b602a..00000000 --- a/src/main/java/seng302/models/Race.java +++ /dev/null @@ -1,198 +0,0 @@ -package seng302.models; - -import seng302.models.mark.Mark; - -import java.util.*; - -/** - * Race class containing the boats and legs in the race - * Created by mra106 on 8/3/2017. - */ -public class Race { - - private ArrayList boats; // The boats in the race - private ArrayList finishingOrder; // The order in which the boats finish the race - private HashMap events = new HashMap<>(); // The events that occur in the race - private List course; // Marks in the race - private long startTime = 0; - private double timeScale = 1; - private boolean raceFinished = false; // Race is finished - private int raceTime = -2; // Current time in the race - - /** - * Race class containing the boats and legs in the race - */ - public Race() { - this.boats = new ArrayList<>(); - this.finishingOrder = new ArrayList<>(); - this.course = new ArrayList<>(); - } - - /** - * Add a boat to the race - * - * @param boat, the boat to add - */ - public void addBoat(Yacht boat) { - boats.add(boat); - } - - /** - * Returns a list of boats in a random order - * - * @return a list of boats - */ - public Yacht[] getShuffledBoats() { - // Shuffle the list of boats - long seed = System.nanoTime(); - Collections.shuffle(this.boats, new Random(seed)); - - return boats.toArray(new Yacht[boats.size()]); - } - - /** - * Returns a list of boats in the order that they - * finished the race (position 0 is first place) - * - * @return a list of boats - */ - public Yacht[] getFinishedBoats() { - return this.finishingOrder.toArray(new Yacht[this.finishingOrder.size()]); - } - - - /** - * Returns a list of boats in the race - * - * @return a list of the boats competing in the race - */ - public Yacht[] getBoats() { - return boats.toArray(new Yacht[boats.size()]); - } - - /** - * Sets time scale - * - * @param timeScale - */ - public void setTimeScale(double timeScale) { - this.timeScale = timeScale; - } - - /** - * Generate all events that will happen during the race. - */ - private void generateEvents() { - - for (Yacht boat : this.boats) { - double totalDistance = 0; - int numberOfMarks = this.course.size(); - - for (int i = 0; i < numberOfMarks; i++) { - Double time = (totalDistance / boat.getVelocity() / timeScale); - - // If there are singleMarks after this event - if (i < numberOfMarks - 1) { - Event event = new Event(time, boat, course.get(i), course.get(i + 1), i); - - try { - events.get(boat).add(event); - - } catch (NullPointerException e) { - events.put(boat, new ArrayList<>(Arrays.asList(event))); - } - totalDistance += event.getDistanceBetweenMarks(); - //System.out.println(totalDistance); - //System.out.println(boat.getVelocity()); - } - - // There are no more marks after this event - - else{ - Event event = new Event(time, boat, course.get(i), i); - events.get(boat).add(event); - } - } - } - } - - - /** - * Starts a race and generates all events for the race. - */ - public void startRace() { - // record start time. - this.startTime = System.currentTimeMillis(); - generateEvents(); - } - - /** - * Set the race course - * @param course a list of marks in the course - */ - public void addCourse(List course) { - this.course = course; - } - - /** - * Get a list of marks in the course - * @return - */ - public List getCourse() { - return course; - } - - /** - * Get a map of the events in the race - * @return - */ - public HashMap getEvents() { - return events; - } - - /** - * Set a boat as finished - * @param boat The boat that has finished the race/home/cosc/student/wmu16 - */ - public void setBoatFinished(Yacht boat){ - this.finishingOrder.add(boat); - } - - /** - * Set the race as finished - */ - public void setRaceFinished(){ - this.raceFinished = true; - } - - /** - * Return whether or not the race is finished - * @return true if the race is finished - */ - public boolean isRaceFinished(){ - return this.raceFinished; - } - - /** - * Set the race time - * @param raceTime the race time in seconds - */ - public void setRaceTime(int raceTime){ - this.raceTime = raceTime; - } - - /** - * Return the race time - * @return the race time in seconds - */ - public int getRaceTime(){ - return this.raceTime; - } - - /** - * Increment the race time by one second - */ - public void incrementRaceTime(){ - this.raceTime += this.timeScale; - } -} \ No newline at end of file diff --git a/src/main/java/seng302/models/mark/MarkGroup.java b/src/main/java/seng302/models/mark/MarkGroup.java index 29931e01..78a97d58 100644 --- a/src/main/java/seng302/models/mark/MarkGroup.java +++ b/src/main/java/seng302/models/mark/MarkGroup.java @@ -53,8 +53,8 @@ public class MarkGroup extends RaceObject { }; super.getChildren().add(markCircle); } else { - marks.add(((GateMark) mark).getSingleMark1()); - marks.add(((GateMark) mark).getSingleMark2()); +// marks.add(((GateMark) mark).getSingleMark1()); +// marks.add(((GateMark) mark).getSingleMark2()); nodePixelVelocitiesX = new double[]{0d,0d}; nodePixelVelocitiesY = new double[]{0d,0d}; nodeDestinations = new Point2D[2]; diff --git a/src/main/java/seng302/models/parsers/ConfigParser.java b/src/main/java/seng302/models/parsers/ConfigParser.java deleted file mode 100644 index 1d870c67..00000000 --- a/src/main/java/seng302/models/parsers/ConfigParser.java +++ /dev/null @@ -1,78 +0,0 @@ -package seng302.models.parsers; - - -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; - -import java.util.DoubleSummaryStatistics; - -public class ConfigParser extends FileParser { - - private Document doc; - - public ConfigParser(String path) { - super(path); - this.doc = this.parseFile(); - } - - /** - * Gets wind direction from config file. - * - * @return a double type degree, or 0 if no value or invalid value is found - */ - public double getWindDirection() { - return getDoubleByTagName("wind-direction", 0.0); - } - - /** - * Gets a non negative time scale for the race - * - * @return a double type scale, or 0 if no scale or invalid scale is found - */ - public double getTimeScale() { - return getDoubleByTagName("time-scale", 1.0); - } - - /** - * Gets a double type number by given tag name found in xml file - * - * @param tagName a string of tag name - * @param defaultVal value returned if no value or invalid value is found - * @return value found - */ - public double getDoubleByTagName(String tagName, double defaultVal) { - double val = defaultVal; - try { - Node node = this.doc.getElementsByTagName(tagName).item(0); - if (node.getNodeType() == Node.ELEMENT_NODE) { - Element element = (Element) node; - val = Double.valueOf(element.getTextContent()); - } - } catch (Exception e) { - } finally { - return val; - } - } - - /** - * Gets a string by given tag name found in xml file - * - * @param tagName a string of tag name - * @param defaultVal a string returned if no value or invalid value is found - * @return string found - */ - public String getStringByTagName(String tagName, String defaultVal) { - String string = defaultVal; - try { - Node node = this.doc.getElementsByTagName(tagName).item(0); - if (node.getNodeType() == Node.ELEMENT_NODE) { - Element element = (Element) node; - string = element.getTextContent(); - } - } catch (Exception e) { - } finally { - return string; - } - } -} diff --git a/src/main/java/seng302/models/parsers/CourseParser.java b/src/main/java/seng302/models/parsers/CourseParser.java deleted file mode 100644 index ae7f7856..00000000 --- a/src/main/java/seng302/models/parsers/CourseParser.java +++ /dev/null @@ -1,145 +0,0 @@ -package seng302.models.parsers; - -import org.w3c.dom.*; -import seng302.models.mark.*; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.NoSuchElementException; - -/** - * parse a course xml file - * Created by Haoming Yin (hyi25) on 16/3/2017 - */ -public class CourseParser extends FileParser { - - private Document doc; - private HashMap marks = new HashMap<>(); - - public CourseParser(String path) { - super(path); - this.doc = this.parseFile(); - } - - /** - * create a mark by given node - * - * @param node - * @return a mark, or null if fails to create a mark - */ - private SingleMark generateSingleMark(Node node) { - try { - if (node.getNodeType() == Node.ELEMENT_NODE) { - Element element = (Element) node; - String name = element.getElementsByTagName("name").item(0).getTextContent(); - double lat = Double.valueOf(element.getElementsByTagName("latitude").item(0).getTextContent()); - double lon = Double.valueOf(element.getElementsByTagName("longitude").item(0).getTextContent()); - int id = Integer.valueOf(element.getElementsByTagName("id").item(0).getTextContent()); - SingleMark singleMark = new SingleMark(name, lat, lon, id); - return singleMark; - } else { - throw new NoSuchElementException("Cannot generate a mark by given node."); - } - } catch (Exception e) { - e.printStackTrace(); - return null; - } - } - - /** - * generate an arrayList of gates - * - * @return an arrayList of gates, or null if no gate has been found. - */ - private void generateGateMarks() { - ArrayList gateMarks = new ArrayList<>(); - - try { - NodeList nodes = doc.getElementsByTagName("gate"); - - for (int i = 0; i < nodes.getLength(); i++) { - Node node = nodes.item(i); - - if (node.getNodeType() == Node.ELEMENT_NODE) { - Element element = (Element) node; - String name = element.getElementsByTagName("name").item(0).getTextContent(); - SingleMark mark1 = generateSingleMark(element.getElementsByTagName("mark").item(0)); - SingleMark mark2 = generateSingleMark(element.getElementsByTagName("mark").item(1)); - GateMark gateMark; - if (name.equals("Start") || name.equals("Finish")) - gateMark = new GateMark(name, MarkType.CLOSED_GATE, mark1, mark2, mark1.getLatitude(), mark1.getLongitude()); - else - gateMark = new GateMark(name, MarkType.OPEN_GATE, mark1, mark2, mark1.getLatitude(), mark1.getLongitude()); - marks.put(name, gateMark); - } - } - } catch (Exception e) { - e.printStackTrace(); - } - } - - /** - * generate an arrayList of marks - * - * @return an arrayList of marks, or null if no gate has been found. - */ - private void generateSingleMarks() { - ArrayList singleMarks = new ArrayList<>(); - - try { - // find the "marks" tag - Node node = doc.getElementsByTagName("marks").item(0); - // iterate all "marks"'s children - for (Node n = node.getFirstChild(); n != null; n = n.getNextSibling()) { - // if node's tag name is "mark" - if (n.getNodeType() == Node.ELEMENT_NODE) { - Element element = (Element) n; - if (element.getNodeName() == "mark") { - Mark mark = generateSingleMark(n); - marks.put(mark.getName(), mark); - } - } - } - } catch (Exception e) { - e.printStackTrace(); - } - } - - /** - * return the order of all the marks along a course - * - * @return an arrayList of the names of ordered course marks - */ - private ArrayList getOrder() { - ArrayList markOrder = new ArrayList<>(); - - try { - Node orderNode = doc.getElementsByTagName("order").item(0); - for (Node node = orderNode.getFirstChild(); node != null; node = node.getNextSibling()) { - if (node.getNodeType() == Node.ELEMENT_NODE) { - Element element = (Element) node; - String name = element.getTextContent(); - markOrder.add(name); - } - } - } catch (Exception e) { - e.printStackTrace(); - } - return markOrder; - } - - public ArrayList getCourse() { - generateSingleMarks(); - generateGateMarks(); - ArrayList course = new ArrayList<>(); - try { - for (String mark : getOrder()) { - course.add(marks.get(mark)); - } - } catch (Exception e) { - e.printStackTrace(); - } - return course; - } -} diff --git a/src/main/java/seng302/models/parsers/FileParser.java b/src/main/java/seng302/models/parsers/FileParser.java deleted file mode 100644 index be162b9e..00000000 --- a/src/main/java/seng302/models/parsers/FileParser.java +++ /dev/null @@ -1,54 +0,0 @@ -package seng302.models.parsers; - -import org.w3c.dom.Document; -import org.xml.sax.InputSource; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.StringReader; - -/** - * Created by Haoming Yin (hyi25) on 16/3/2017 - */ -public abstract class FileParser { - - private String filePath; - - public FileParser() {} - - public FileParser(String path) { - this.filePath = path; - } - - protected Document parseFile() { - try { - InputStream is = getClass().getResourceAsStream(this.filePath); - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - DocumentBuilder builder = factory.newDocumentBuilder(); - Document doc = builder.parse(is); - // optional, in order to recover info from broken line. - doc.getDocumentElement().normalize(); - return doc; - } catch (Exception e) { - e.printStackTrace(); - return null; - } - } - - protected Document parseFile(String xmlString) { - try { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - DocumentBuilder builder = factory.newDocumentBuilder(); - Document doc = builder.parse(new InputSource(new StringReader(xmlString))); - // optional, in order to recover info from broken line. - doc.getDocumentElement().normalize(); - return doc; - } catch (Exception e) { - e.printStackTrace(); - } - return null; - } -} diff --git a/src/main/java/seng302/models/parsers/TeamsParser.java b/src/main/java/seng302/models/parsers/TeamsParser.java deleted file mode 100644 index fae0a743..00000000 --- a/src/main/java/seng302/models/parsers/TeamsParser.java +++ /dev/null @@ -1,64 +0,0 @@ -//package seng302.models.parsers; -// -//import org.w3c.dom.*; -//import seng302.models.Yacht; -// -//import java.util.ArrayList; -//import java.util.NoSuchElementException; -// -//public class TeamsParser extends FileParser { -// -// private Document doc; -// -// public TeamsParser(String path) { -// super(path); -// this.doc = this.parseFile(); -// } -// -// /** -// * Create a boat instance by a given team node -// * @param node a boat node containing name, alias and velocity -// * @return an instance of Boat -// */ -// private Yacht parseBoat(Node node) { -// try { -// if (node.getNodeType() == Node.ELEMENT_NODE) { -// Element element = (Element) node; -// String name = element.getElementsByTagName("name").item(0).getTextContent(); -// String alias = element.getElementsByTagName("alias").item(0).getTextContent(); -// double velocity = Double.valueOf(element.getElementsByTagName("velocity").item(0).getTextContent()); -// int id = Integer.valueOf(element.getElementsByTagName("id").item(0).getTextContent()); -// Yacht boat = new Yacht(name, velocity, alias, id); -// return boat; -// } else { -// throw new NoSuchElementException("Cannot generate a boat by given node"); -// } -// } catch (Exception e) { -// e.printStackTrace(); -// return null; -// } -// } -// -// /** -// * Create an arraylist of boats instance. -// * @return an arraylist of boats in teams file -// */ -// public ArrayList getBoats() { -// ArrayList boats = new ArrayList<>(); -// -// try { -// NodeList nodes = this.doc.getElementsByTagName("team"); -// for (int i = 0; i < nodes.getLength(); i++) { -// Node node = nodes.item(i); -// boats.add(parseBoat(node)); -// } -// return boats; -// } catch (Exception e) { -// e.printStackTrace(); -// return null; -// } -// } -// -// -//} -// diff --git a/src/main/java/seng302/models/parsers/XMLParser.java b/src/main/java/seng302/models/parsers/XMLParser.java index f8d30460..51c7f69f 100644 --- a/src/main/java/seng302/models/parsers/XMLParser.java +++ b/src/main/java/seng302/models/parsers/XMLParser.java @@ -5,6 +5,7 @@ import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import seng302.models.Yacht; +import seng302.models.mark.MarkType; import java.util.ArrayList; import java.util.HashMap; @@ -301,6 +302,7 @@ public class XMLParser { public class CompoundMark { private Integer markID; private String cMarkName; + private MarkType markType; private ArrayList marks; CompoundMark(Node compoundMark) { @@ -308,6 +310,12 @@ public class XMLParser { this.markID = getNodeAttributeInt(compoundMark, "CompoundMarkID"); this.cMarkName = getNodeAttributeString(compoundMark, "Name"); NodeList childMarks = compoundMark.getChildNodes(); + if (childMarks.getLength() > 1){ + markType = MarkType.OPEN_GATE; + } else { + markType = MarkType.SINGLE_MARK; + } + for (int i = 0; i < childMarks.getLength(); i++) { Node markNode = childMarks.item(i); if (markNode.getNodeName().equals("Mark")) { diff --git a/src/main/resources/views/RaceView.fxml b/src/main/resources/views/RaceView.fxml index 3c148485..0eca8639 100644 --- a/src/main/resources/views/RaceView.fxml +++ b/src/main/resources/views/RaceView.fxml @@ -1,21 +1,9 @@ - - - - - - - - - - - - diff --git a/src/test/java/seng302/RaceTest.java b/src/test/java/seng302/RaceTest.java deleted file mode 100644 index 2784cd47..00000000 --- a/src/test/java/seng302/RaceTest.java +++ /dev/null @@ -1,41 +0,0 @@ -package seng302; - -import org.junit.Test; -import seng302.models.Race; -import seng302.models.Yacht; - -import java.lang.reflect.Array; - -import static org.junit.Assert.assertEquals; - -/** - * Unit test for the Race class. - */ -public class RaceTest { - /** - * Test that all boats were added to the race - */ - @Test - public void testAddingBoatsToRace() { - Yacht boat1 = new Yacht("Team 1"); - Yacht boat2 = new Yacht("Team 2"); - - Race race = new Race(); - race.addBoat(boat1); - race.addBoat(boat2); - - assertEquals(Array.getLength(race.getBoats()), 2); - } - - @Test - public void testGetShuffledBoats(){ - Yacht boat1 = new Yacht("Team 1"); - Yacht boat2 = new Yacht("Team 2"); - - Race race = new Race(); - race.addBoat(boat1); - race.addBoat(boat2); - - assertEquals(Array.getLength(race.getShuffledBoats()), 2); - } -} diff --git a/src/test/java/seng302/models/parsers/ConfigParserTest.java b/src/test/java/seng302/models/parsers/ConfigParserTest.java deleted file mode 100644 index 8a0c0c8c..00000000 --- a/src/test/java/seng302/models/parsers/ConfigParserTest.java +++ /dev/null @@ -1,42 +0,0 @@ -package seng302.models.parsers; - -import org.junit.Before; -import org.junit.Test; - -import static org.junit.Assert.*; - -/** - * Created by Haoming on 23/03/17. - */ -public class ConfigParserTest { - - private ConfigParser cp; - - @Before - public void initializeParser() throws Exception { - cp = new ConfigParser("/config/config.xml"); - } - - @Test - public void getWindDirection() throws Exception { - assertEquals(135, cp.getWindDirection(), 1e-10); - } - - @Test - public void getTimeScale() throws Exception { - assertEquals(10.0, cp.getTimeScale(), 1e-10); - } - - @Test - public void getDoubleByTagName() throws Exception { - assertEquals(6, cp.getDoubleByTagName("race-size", 0), 1e-10); - assertEquals(100, cp.getDoubleByTagName("noTag", 100), 1e-10); - } - - @Test - public void getStringByTagName() throws Exception { - assertEquals("AC35", cp.getStringByTagName("race-name", "11")); - assertEquals("oops", cp.getStringByTagName("noTag", "oops")); - } - -} \ No newline at end of file diff --git a/src/test/java/seng302/models/parsers/CourseParserTest.java b/src/test/java/seng302/models/parsers/CourseParserTest.java deleted file mode 100644 index 48bf9d92..00000000 --- a/src/test/java/seng302/models/parsers/CourseParserTest.java +++ /dev/null @@ -1,59 +0,0 @@ -package seng302.models.parsers; - -import org.junit.Before; -import org.junit.Test; -import seng302.models.mark.*; - -import java.util.ArrayList; - -import static org.junit.Assert.*; - -/** - * To test if course parser works as expected. - * Created by Haoming on 17/03/17. - */ -public class CourseParserTest { - - private CourseParser cp; - - @Before - public void initializeParser() throws Exception { - cp = new CourseParser("/config/course.xml"); - } - - @Test - public void getGates() throws Exception { - ArrayList course = cp.getCourse(); - - - GateMark gateMark1 = (GateMark) course.get(0); - assertEquals(57.670633, gateMark1.getSingleMark2().getLatitude(), 0.00000001); - assertEquals(11.8281330, gateMark1.getSingleMark2().getLongitude(), 0.00000001); - - GateMark gateMark2 = (GateMark) course.get(5); - - assertEquals("Finish1", gateMark2.getSingleMark1().getName()); - assertEquals("Finish2", gateMark2.getSingleMark2().getName()); - assertEquals(57.671824, gateMark2.getSingleMark2().getLatitude(), 0.00000001); - assertEquals(11.844795, gateMark2.getSingleMark2().getLongitude(), 0.00000001); - } - - @Test - public void getMarks() throws Exception { - ArrayList course = cp.getCourse(); - assertEquals("Mid Mark", course.get(1).getName()); - } - - @Test - public void getOrder() { - ArrayList course = cp.getCourse(); - assertEquals(6, course.size()); - assertEquals("Start", course.get(0).getName()); - assertEquals("Mid Mark", course.get(1).getName()); - assertEquals("Leeward Gate", course.get(2).getName()); - assertEquals("Windward Gate", course.get(3).getName()); - assertEquals("Leeward Gate", course.get(4).getName()); - assertEquals("Finish", course.get(5).getName()); - } - -} \ No newline at end of file From 63514cfafbee35873d1236988aa9e68b6f79ce8e Mon Sep 17 00:00:00 2001 From: Peter Galloway Date: Sun, 14 May 2017 20:20:14 +1200 Subject: [PATCH 04/32] deleted duplicated packet type class #story[923] --- .../seng302/models/parsers/PacketType.java | 53 ------------------- .../seng302/models/parsers/StreamPacket.java | 2 + .../models/parsers/packets/PacketType.java | 2 - 3 files changed, 2 insertions(+), 55 deletions(-) delete mode 100644 src/main/java/seng302/models/parsers/PacketType.java diff --git a/src/main/java/seng302/models/parsers/PacketType.java b/src/main/java/seng302/models/parsers/PacketType.java deleted file mode 100644 index 66b86207..00000000 --- a/src/main/java/seng302/models/parsers/PacketType.java +++ /dev/null @@ -1,53 +0,0 @@ -package seng302.models.parsers; - -/** - * Created by Kusal on 4/24/2017. - */ -public enum PacketType { - HEARTBEAT, - RACE_STATUS, - DISPLAY_TEXT_MESSAGE, - XML_MESSAGE, - RACE_START_STATUS, - YACHT_EVENT_CODE, - YACHT_ACTION_CODE, - CHATTER_TEXT, - BOAT_LOCATION, - MARK_ROUNDING, - COURSE_WIND, - AVG_WIND, - OTHER; - - static PacketType assignPacketType(int packetType){ - switch(packetType){ - case 1: - return HEARTBEAT; - case 12: - return RACE_STATUS; - case 20: - return DISPLAY_TEXT_MESSAGE; - case 26: - return XML_MESSAGE; - case 27: - return RACE_START_STATUS; - case 29: - return YACHT_EVENT_CODE; - case 31: - return YACHT_ACTION_CODE; - case 36: - return CHATTER_TEXT; - case 37: - return BOAT_LOCATION; - case 38: - return MARK_ROUNDING; - case 44: - return COURSE_WIND; - case 47: - return AVG_WIND; - default: - } - return OTHER; - } - - -} diff --git a/src/main/java/seng302/models/parsers/StreamPacket.java b/src/main/java/seng302/models/parsers/StreamPacket.java index 5c2c0706..f4ba3b81 100644 --- a/src/main/java/seng302/models/parsers/StreamPacket.java +++ b/src/main/java/seng302/models/parsers/StreamPacket.java @@ -1,5 +1,7 @@ package seng302.models.parsers; +import seng302.models.parsers.packets.PacketType; + /** * Created by kre39 on 23/04/17. */ diff --git a/src/main/java/seng302/models/parsers/packets/PacketType.java b/src/main/java/seng302/models/parsers/packets/PacketType.java index f522dec9..4367ca90 100644 --- a/src/main/java/seng302/models/parsers/packets/PacketType.java +++ b/src/main/java/seng302/models/parsers/packets/PacketType.java @@ -48,6 +48,4 @@ public enum PacketType { } return OTHER; } - - } From ae5678482b7d940e9eea22fdc81dba536839cc20 Mon Sep 17 00:00:00 2001 From: Peter Galloway Date: Sun, 14 May 2017 20:26:49 +1200 Subject: [PATCH 05/32] changed package "parsers" to be called "stream" #story[923] --- src/main/java/seng302/App.java | 4 ++-- .../java/seng302/controllers/CanvasController.java | 14 ++++---------- src/main/java/seng302/controllers/Controller.java | 10 ++-------- .../seng302/controllers/RaceViewController.java | 5 +---- .../models/{parsers => stream}/StreamPacket.java | 4 ++-- .../models/{parsers => stream}/StreamParser.java | 6 +++--- .../models/{parsers => stream}/StreamReceiver.java | 6 ++---- .../models/{parsers => stream}/XMLParser.java | 3 +-- .../packets/BoatPositionPacket.java | 2 +- .../{parsers => stream}/packets/PacketType.java | 2 +- .../{parsers => stream}/packets/StreamPacket.java | 2 +- .../{parsers => stream}/StreamReceiverTest.java | 2 +- .../{parsers => stream}/TeamsParserTest.java | 0 13 files changed, 21 insertions(+), 39 deletions(-) rename src/main/java/seng302/models/{parsers => stream}/StreamPacket.java (93%) rename src/main/java/seng302/models/{parsers => stream}/StreamParser.java (99%) rename src/main/java/seng302/models/{parsers => stream}/StreamReceiver.java (97%) rename src/main/java/seng302/models/{parsers => stream}/XMLParser.java (99%) rename src/main/java/seng302/models/{parsers => stream}/packets/BoatPositionPacket.java (95%) rename src/main/java/seng302/models/{parsers => stream}/packets/PacketType.java (96%) rename src/main/java/seng302/models/{parsers => stream}/packets/StreamPacket.java (95%) rename src/test/java/seng302/models/{parsers => stream}/StreamReceiverTest.java (99%) rename src/test/java/seng302/models/{parsers => stream}/TeamsParserTest.java (100%) diff --git a/src/main/java/seng302/App.java b/src/main/java/seng302/App.java index 19a30595..92aab87a 100644 --- a/src/main/java/seng302/App.java +++ b/src/main/java/seng302/App.java @@ -5,8 +5,8 @@ import javafx.fxml.FXMLLoader; import javafx.scene.Parent; import javafx.scene.Scene; import javafx.stage.Stage; -import seng302.models.parsers.StreamParser; -import seng302.models.parsers.StreamReceiver; +import seng302.models.stream.StreamParser; +import seng302.models.stream.StreamReceiver; import seng302.server.ServerThread; public class App extends Application diff --git a/src/main/java/seng302/controllers/CanvasController.java b/src/main/java/seng302/controllers/CanvasController.java index d477734d..a7ed44ad 100644 --- a/src/main/java/seng302/controllers/CanvasController.java +++ b/src/main/java/seng302/controllers/CanvasController.java @@ -5,23 +5,17 @@ import javafx.beans.property.SimpleDoubleProperty; import javafx.fxml.FXML; import javafx.geometry.Point2D; import javafx.scene.Group; -import javafx.scene.Node; import javafx.scene.canvas.Canvas; import javafx.scene.canvas.GraphicsContext; import javafx.scene.layout.AnchorPane; -import javafx.scene.layout.Pane; import javafx.scene.paint.Color; -import javafx.scene.shape.Polygon; import javafx.scene.text.Font; -import javafx.stage.Stage; import seng302.models.*; import seng302.models.mark.*; -import seng302.models.parsers.StreamParser; -import seng302.models.parsers.StreamReceiver; -import seng302.models.parsers.packets.BoatPositionPacket; -import seng302.models.parsers.XMLParser; -import seng302.models.parsers.XMLParser.RaceXMLObject.CompoundMark; -import seng302.models.parsers.XMLParser.RaceXMLObject.Limit; +import seng302.models.stream.StreamParser; +import seng302.models.stream.packets.BoatPositionPacket; +import seng302.models.stream.XMLParser; +import seng302.models.stream.XMLParser.RaceXMLObject.Limit; import seng302.models.mark.Mark; import java.text.DecimalFormat; diff --git a/src/main/java/seng302/controllers/Controller.java b/src/main/java/seng302/controllers/Controller.java index eeae57cc..8eb2eee2 100644 --- a/src/main/java/seng302/controllers/Controller.java +++ b/src/main/java/seng302/controllers/Controller.java @@ -5,7 +5,6 @@ import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.fxml.FXML; import javafx.fxml.FXMLLoader; -import javafx.fxml.Initializable; import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.control.TableColumn; @@ -15,16 +14,11 @@ import javafx.scene.layout.AnchorPane; import javafx.scene.layout.Pane; import javafx.scene.paint.Color; import seng302.models.Yacht; -import seng302.models.parsers.StreamParser; -import seng302.models.parsers.XMLParser; +import seng302.models.stream.StreamParser; +import seng302.models.stream.XMLParser; import java.io.IOException; -import java.net.URL; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.*; -import java.util.ResourceBundle; import java.util.Timer; import java.util.TimerTask; diff --git a/src/main/java/seng302/controllers/RaceViewController.java b/src/main/java/seng302/controllers/RaceViewController.java index f8eed705..a1bb9651 100644 --- a/src/main/java/seng302/controllers/RaceViewController.java +++ b/src/main/java/seng302/controllers/RaceViewController.java @@ -5,20 +5,17 @@ import javafx.animation.Timeline; import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; import javafx.fxml.FXML; -import javafx.fxml.FXMLLoader; import javafx.scene.control.CheckBox; import javafx.scene.control.Slider; import javafx.scene.layout.AnchorPane; -import javafx.scene.layout.Pane; import javafx.scene.layout.VBox; import javafx.scene.paint.Color; import javafx.scene.text.Text; import javafx.util.Duration; import javafx.util.StringConverter; import seng302.models.*; -import seng302.models.parsers.StreamParser; +import seng302.models.stream.StreamParser; -import java.io.IOException; import java.util.*; /** diff --git a/src/main/java/seng302/models/parsers/StreamPacket.java b/src/main/java/seng302/models/stream/StreamPacket.java similarity index 93% rename from src/main/java/seng302/models/parsers/StreamPacket.java rename to src/main/java/seng302/models/stream/StreamPacket.java index f4ba3b81..1cb35bb5 100644 --- a/src/main/java/seng302/models/parsers/StreamPacket.java +++ b/src/main/java/seng302/models/stream/StreamPacket.java @@ -1,6 +1,6 @@ -package seng302.models.parsers; +package seng302.models.stream; -import seng302.models.parsers.packets.PacketType; +import seng302.models.stream.packets.PacketType; /** * Created by kre39 on 23/04/17. diff --git a/src/main/java/seng302/models/parsers/StreamParser.java b/src/main/java/seng302/models/stream/StreamParser.java similarity index 99% rename from src/main/java/seng302/models/parsers/StreamParser.java rename to src/main/java/seng302/models/stream/StreamParser.java index dce7e172..fb6e1d1e 100644 --- a/src/main/java/seng302/models/parsers/StreamParser.java +++ b/src/main/java/seng302/models/stream/StreamParser.java @@ -1,12 +1,12 @@ -package seng302.models.parsers; +package seng302.models.stream; import org.w3c.dom.Document; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import seng302.models.Yacht; -import seng302.models.parsers.packets.BoatPositionPacket; -import seng302.models.parsers.packets.StreamPacket; +import seng302.models.stream.packets.BoatPositionPacket; +import seng302.models.stream.packets.StreamPacket; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; diff --git a/src/main/java/seng302/models/parsers/StreamReceiver.java b/src/main/java/seng302/models/stream/StreamReceiver.java similarity index 97% rename from src/main/java/seng302/models/parsers/StreamReceiver.java rename to src/main/java/seng302/models/stream/StreamReceiver.java index 65d7c525..b3303806 100644 --- a/src/main/java/seng302/models/parsers/StreamReceiver.java +++ b/src/main/java/seng302/models/stream/StreamReceiver.java @@ -1,13 +1,11 @@ -package seng302.models.parsers; +package seng302.models.stream; -import seng302.models.parsers.packets.StreamPacket; +import seng302.models.stream.packets.StreamPacket; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.Socket; -import java.util.ArrayList; -import java.util.Collection; import java.util.Comparator; import java.util.concurrent.PriorityBlockingQueue; import java.util.zip.CRC32; diff --git a/src/main/java/seng302/models/parsers/XMLParser.java b/src/main/java/seng302/models/stream/XMLParser.java similarity index 99% rename from src/main/java/seng302/models/parsers/XMLParser.java rename to src/main/java/seng302/models/stream/XMLParser.java index 51c7f69f..6349d07f 100644 --- a/src/main/java/seng302/models/parsers/XMLParser.java +++ b/src/main/java/seng302/models/stream/XMLParser.java @@ -1,4 +1,4 @@ -package seng302.models.parsers; +package seng302.models.stream; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -9,7 +9,6 @@ import seng302.models.mark.MarkType; import java.util.ArrayList; import java.util.HashMap; -import java.util.List; import java.util.Map; /** diff --git a/src/main/java/seng302/models/parsers/packets/BoatPositionPacket.java b/src/main/java/seng302/models/stream/packets/BoatPositionPacket.java similarity index 95% rename from src/main/java/seng302/models/parsers/packets/BoatPositionPacket.java rename to src/main/java/seng302/models/stream/packets/BoatPositionPacket.java index d6f0700d..859223e0 100644 --- a/src/main/java/seng302/models/parsers/packets/BoatPositionPacket.java +++ b/src/main/java/seng302/models/stream/packets/BoatPositionPacket.java @@ -1,4 +1,4 @@ -package seng302.models.parsers.packets; +package seng302.models.stream.packets; public class BoatPositionPacket { private long boatId; diff --git a/src/main/java/seng302/models/parsers/packets/PacketType.java b/src/main/java/seng302/models/stream/packets/PacketType.java similarity index 96% rename from src/main/java/seng302/models/parsers/packets/PacketType.java rename to src/main/java/seng302/models/stream/packets/PacketType.java index 4367ca90..0fd0be84 100644 --- a/src/main/java/seng302/models/parsers/packets/PacketType.java +++ b/src/main/java/seng302/models/stream/packets/PacketType.java @@ -1,4 +1,4 @@ -package seng302.models.parsers.packets; +package seng302.models.stream.packets; /** * Created by Kusal on 4/24/2017. diff --git a/src/main/java/seng302/models/parsers/packets/StreamPacket.java b/src/main/java/seng302/models/stream/packets/StreamPacket.java similarity index 95% rename from src/main/java/seng302/models/parsers/packets/StreamPacket.java rename to src/main/java/seng302/models/stream/packets/StreamPacket.java index 4f10008c..22f2fe56 100644 --- a/src/main/java/seng302/models/parsers/packets/StreamPacket.java +++ b/src/main/java/seng302/models/stream/packets/StreamPacket.java @@ -1,4 +1,4 @@ -package seng302.models.parsers.packets; +package seng302.models.stream.packets; /** * Created by kre39 on 23/04/17. diff --git a/src/test/java/seng302/models/parsers/StreamReceiverTest.java b/src/test/java/seng302/models/stream/StreamReceiverTest.java similarity index 99% rename from src/test/java/seng302/models/parsers/StreamReceiverTest.java rename to src/test/java/seng302/models/stream/StreamReceiverTest.java index c7951e3b..ff9755bb 100644 --- a/src/test/java/seng302/models/parsers/StreamReceiverTest.java +++ b/src/test/java/seng302/models/stream/StreamReceiverTest.java @@ -1,4 +1,4 @@ -package seng302.models.parsers; +package seng302.models.stream; import org.junit.Before; import org.junit.Test; diff --git a/src/test/java/seng302/models/parsers/TeamsParserTest.java b/src/test/java/seng302/models/stream/TeamsParserTest.java similarity index 100% rename from src/test/java/seng302/models/parsers/TeamsParserTest.java rename to src/test/java/seng302/models/stream/TeamsParserTest.java From 256ec046fc7cad53378e8a1d48d682eb25f2804b Mon Sep 17 00:00:00 2001 From: Peter Galloway Date: Sun, 14 May 2017 22:12:16 +1200 Subject: [PATCH 06/32] adjusted givePointsXY to try and use the marks from the XML parser, stopped partway as the marks from the XML parser and the standard marks need to be merged before this can be fixed properly #story[923] --- .../seng302/controllers/CanvasController.java | 37 +++++++++---------- .../java/seng302/models/stream/XMLParser.java | 1 + 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/main/java/seng302/controllers/CanvasController.java b/src/main/java/seng302/controllers/CanvasController.java index a7ed44ad..b5642755 100644 --- a/src/main/java/seng302/controllers/CanvasController.java +++ b/src/main/java/seng302/controllers/CanvasController.java @@ -389,25 +389,24 @@ public class CanvasController { * Give all markers in the course an x,y location relative to a given reference with a known x,y location. Distances * are scaled according to the distanceScaleFactor variable. */ -// private void givePointsXY() { -// List allPoints = new ArrayList<>(raceViewController.getRace().getCourse()); -// List processed = new ArrayList<>(); -// RaceObject markGroup; -// -// for (Mark mark : allPoints) { -// if (!processed.contains(mark)) { -// if (mark.getMarkType() != MarkType.SINGLE_MARK) { -// GateMark gateMark = (GateMark) mark; -// markGroup = new MarkGroup(mark, findScaledXY(gateMark.getSingleMark1()), findScaledXY(gateMark.getSingleMark2())); -// raceObjects.add(markGroup); -// } else { -// markGroup = new MarkGroup(mark, findScaledXY(mark)); -// raceObjects.add(markGroup); -// } -// processed.add(mark); -// } -// } -// } + private void givePointsXY() { + List allPoints = StreamParser.getXmlObject().getRaceXML().getCompoundMarks(); + List processed = new ArrayList<>(); + RaceObject markGroup; + + for (XMLParser.RaceXMLObject.CompoundMark mark : allPoints) { + if (!processed.contains(mark)) { + if (mark.getMarkType() != MarkType.SINGLE_MARK) { + markGroup = new MarkGroup(mark, findScaledXY(mark.getMarks().get(0)), findScaledXY(mark.getMarks().get(1))); + raceObjects.add(markGroup); + } else { + markGroup = new MarkGroup(mark, findScaledXY(mark.getMarks().get(0))); + raceObjects.add(markGroup); + } + processed.add(mark); + } + } + } private Point2D findScaledXY (Mark unscaled) { return findScaledXY (minLatPoint.getLatitude(), minLatPoint.getLongitude(), diff --git a/src/main/java/seng302/models/stream/XMLParser.java b/src/main/java/seng302/models/stream/XMLParser.java index 6349d07f..181c1e2f 100644 --- a/src/main/java/seng302/models/stream/XMLParser.java +++ b/src/main/java/seng302/models/stream/XMLParser.java @@ -326,6 +326,7 @@ public class XMLParser { public Integer getMarkID() { return markID; } public String getcMarkName() { return cMarkName; } + public MarkType getMarkType() { return markType; } public ArrayList getMarks() { return marks; } public class Mark { From ccda5f2a2ebee419158b66d8623b6bd8d161017b Mon Sep 17 00:00:00 2001 From: Peter Galloway Date: Mon, 15 May 2017 12:40:11 +1200 Subject: [PATCH 07/32] changing branch name #story[923] --- src/main/java/seng302/controllers/CanvasController.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/seng302/controllers/CanvasController.java b/src/main/java/seng302/controllers/CanvasController.java index b5642755..53582740 100644 --- a/src/main/java/seng302/controllers/CanvasController.java +++ b/src/main/java/seng302/controllers/CanvasController.java @@ -357,6 +357,7 @@ public class CanvasController { } } + /** * Finds the scale factor necessary to fit all race markers within the onscreen map and assigns it to distanceScaleFactor * Returns the max horizontal distance of the map. From c4fe116267d53dfaea558763fb33a71c0cfcf71a Mon Sep 17 00:00:00 2001 From: Calum Date: Mon, 15 May 2017 15:17:54 +1200 Subject: [PATCH 08/32] MarkGroups refactored to be independent of BoatGroups as their functionality has diverged. #issue[10] #refactor --- .../seng302/controllers/CanvasController.java | 81 ++++++--- .../controllers/RaceViewController.java | 20 +-- src/main/java/seng302/models/BoatGroup.java | 36 +++- src/main/java/seng302/models/RaceObject.java | 87 ---------- .../java/seng302/models/mark/MarkGroup.java | 159 +++--------------- 5 files changed, 110 insertions(+), 273 deletions(-) delete mode 100644 src/main/java/seng302/models/RaceObject.java diff --git a/src/main/java/seng302/controllers/CanvasController.java b/src/main/java/seng302/controllers/CanvasController.java index 53582740..a2e00a23 100644 --- a/src/main/java/seng302/controllers/CanvasController.java +++ b/src/main/java/seng302/controllers/CanvasController.java @@ -17,6 +17,7 @@ import seng302.models.stream.packets.BoatPositionPacket; import seng302.models.stream.XMLParser; import seng302.models.stream.XMLParser.RaceXMLObject.Limit; import seng302.models.mark.Mark; +import seng302.server.simulator.Boat; import java.text.DecimalFormat; import java.util.*; @@ -53,7 +54,8 @@ public class CanvasController { private Mark maxLonPoint; private double referencePointX; private double referencePointY; - private List raceObjects = new ArrayList<>(); + private List markGroups = new ArrayList<>(); + private List boatGroups = new ArrayList<>(); private List raceMarks = new ArrayList<>(); //FRAME RATE @@ -172,21 +174,26 @@ public class CanvasController { gc.fillPolygon(xBoundaryPoints,yBoundaryPoints,yBoundaryPoints.length); } - private void updateRaceObjects(){ - for (RaceObject raceObject : raceObjects) { - raceObject.updatePosition(1000 / 60); + private void updateGroups(){ + for (BoatGroup boatGroup : boatGroups) { + boatGroup.updatePosition(1000 / 60); // some raceObjects will have multiply ID's (for instance gate marks) - for (long id : raceObject.getRaceIds()) { //checking if the current "ID" has any updates associated with it + if (StreamParser.boatPositions.containsKey(boatGroup.getRaceId())) { + moveBoatGroup(boatGroup); + } + } + for (MarkGroup markGroup : markGroups) { + for (int id : markGroup.getRaceIds()) { if (StreamParser.boatPositions.containsKey(id)) { - move(id, raceObject); + moveMarkGroup(id, markGroup); } } } } - private void move(long id, RaceObject raceObject){ - PriorityBlockingQueue movementQueue = StreamParser.boatPositions.get(id); + private void moveBoatGroup(BoatGroup boatGroup) { + PriorityBlockingQueue movementQueue = StreamParser.boatPositions.get(boatGroup.getRaceId()); if (movementQueue.size() > 0){ // BoatPositionPacket positionPacket = movementQueue.peek(); // @@ -202,9 +209,9 @@ public class CanvasController { // if (timeDiff > delayTime) { try { BoatPositionPacket positionPacket = movementQueue.take(); - Point2D p2d = latLonToXY(positionPacket.getLat(), positionPacket.getLon()); + Point2D p2d = findScaledXY(positionPacket.getLat(), positionPacket.getLon()); double heading = 360.0 / 0xffff * positionPacket.getHeading(); - raceObject.setDestination(p2d.getX(), p2d.getY(), heading, positionPacket.getGroundSpeed(), (int) id); + boatGroup.setDestination(p2d.getX(), p2d.getY(), heading, positionPacket.getGroundSpeed(), boatGroup.getRaceId()); } catch (InterruptedException e){ e.printStackTrace(); } @@ -212,6 +219,31 @@ public class CanvasController { } } + void moveMarkGroup (int raceId, MarkGroup markGroup) { + PriorityBlockingQueue movementQueue = StreamParser.boatPositions.get(raceId); + if (movementQueue.size() > 0){ +// BoatPositionPacket positionPacket = movementQueue.peek(); +// +// //this code adds a delay to reading from the movementQueue +// //in case things being put into the movement queue are slightly +// //out of order +// int delayTime = 1000; +// int loopTime = delayTime * 10; +// long timeDiff = (System.currentTimeMillis()%loopTime - positionPacket.getTimeValid()%loopTime); +// if (timeDiff < 0){ +// timeDiff = loopTime + timeDiff; +// } +// if (timeDiff > delayTime) { + try { + BoatPositionPacket positionPacket = movementQueue.take(); + Point2D p2d = findScaledXY(positionPacket.getLat(), positionPacket.getLon()); + markGroup.moveMarkTo(p2d.getX(), p2d.getY(), raceId); + } catch (InterruptedException e){ + e.printStackTrace(); + } + } + } + class ResizableCanvas extends Canvas { ResizableCanvas() { @@ -277,11 +309,11 @@ public class CanvasController { BoatGroup boatGroup = new BoatGroup(boat, boat.getColour()); // boatGroup.moveTo(startingX, startingY, 0d); //boatGroup.setStage(raceViewController.getStage()); - raceObjects.add(boatGroup); + boatGroups.add(boatGroup); boatAnnotations.getChildren().add(boatGroup.getLowPriorityAnnotations()); } group.getChildren().add(boatAnnotations); - group.getChildren().addAll(raceObjects); + group.getChildren().addAll(boatGroups); } /** @@ -393,35 +425,35 @@ public class CanvasController { private void givePointsXY() { List allPoints = StreamParser.getXmlObject().getRaceXML().getCompoundMarks(); List processed = new ArrayList<>(); - RaceObject markGroup; + MarkGroup markGroup; for (XMLParser.RaceXMLObject.CompoundMark mark : allPoints) { if (!processed.contains(mark)) { if (mark.getMarkType() != MarkType.SINGLE_MARK) { markGroup = new MarkGroup(mark, findScaledXY(mark.getMarks().get(0)), findScaledXY(mark.getMarks().get(1))); - raceObjects.add(markGroup); + markGroups.add(markGroup); } else { markGroup = new MarkGroup(mark, findScaledXY(mark.getMarks().get(0))); - raceObjects.add(markGroup); + markGroups.add(markGroup); } processed.add(mark); } } + group.getChildren().addAll(boatGroups); } private Point2D findScaledXY (Mark unscaled) { - return findScaledXY (minLatPoint.getLatitude(), minLatPoint.getLongitude(), - unscaled.getLatitude(), unscaled.getLongitude()); + return findScaledXY (unscaled.getLatitude(), unscaled.getLongitude()); } - private Point2D findScaledXY (double latA, double lonA, double latB, double lonB) { + private Point2D findScaledXY (double unscaledLat, double unscaledLon) { double distanceFromReference; double angleFromReference; int xAxisLocation = (int) referencePointX; int yAxisLocation = (int) referencePointY; - angleFromReference = Mark.calculateHeadingRad(latA, lonA, latB, lonB); - distanceFromReference = Mark.calculateDistance(latA, lonA, latB, lonB); + angleFromReference = Mark.calculateHeadingRad(minLatPoint.getLatitude(), minLatPoint.getLongitude(), unscaledLat, unscaledLon); + distanceFromReference = Mark.calculateDistance(minLatPoint.getLatitude(), minLatPoint.getLongitude(), unscaledLat, unscaledLon); if (angleFromReference >= 0 && angleFromReference <= Math.PI / 2) { xAxisLocation += (int) Math.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference); yAxisLocation -= (int) Math.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference); @@ -441,12 +473,7 @@ public class CanvasController { return new Point2D(xAxisLocation, yAxisLocation); } - - private Point2D latLonToXY (double latitude, double longitude) { - return findScaledXY(minLatPoint.getLatitude(), minLatPoint.getLongitude(), latitude, longitude); - } - - List getRaceObjects() { - return raceObjects; + List getBoatGroups() { + return boatGroups; } } \ No newline at end of file diff --git a/src/main/java/seng302/controllers/RaceViewController.java b/src/main/java/seng302/controllers/RaceViewController.java index a1bb9651..4ff0327d 100644 --- a/src/main/java/seng302/controllers/RaceViewController.java +++ b/src/main/java/seng302/controllers/RaceViewController.java @@ -201,47 +201,35 @@ public class RaceViewController extends Thread{ private void setAnnotations(Integer annotationLevel) { switch (annotationLevel) { case 0: - for (RaceObject ro : includedCanvasController.getRaceObjects()) { - if(ro instanceof BoatGroup) { - BoatGroup bg = (BoatGroup) ro; + for (BoatGroup bg : includedCanvasController.getBoatGroups()) { bg.setTeamNameObjectVisible(false); bg.setVelocityObjectVisible(false); bg.setLineGroupVisible(false); bg.setWakeVisible(false); - } } break; case 1: - for (RaceObject ro : includedCanvasController.getRaceObjects()) { - if(ro instanceof BoatGroup) { - BoatGroup bg = (BoatGroup) ro; + for (BoatGroup bg : includedCanvasController.getBoatGroups()) { bg.setTeamNameObjectVisible(true); bg.setVelocityObjectVisible(false); bg.setLineGroupVisible(false); bg.setWakeVisible(false); - } } break; case 2: - for (RaceObject ro : includedCanvasController.getRaceObjects()) { - if(ro instanceof BoatGroup) { - BoatGroup bg = (BoatGroup) ro; + for (BoatGroup bg : includedCanvasController.getBoatGroups()) { bg.setTeamNameObjectVisible(true); bg.setVelocityObjectVisible(false); bg.setLineGroupVisible(true); bg.setWakeVisible(false); - } } break; case 3: - for (RaceObject ro : includedCanvasController.getRaceObjects()) { - if(ro instanceof BoatGroup) { - BoatGroup bg = (BoatGroup) ro; + for (BoatGroup bg : includedCanvasController.getBoatGroups()) { bg.setTeamNameObjectVisible(true); bg.setVelocityObjectVisible(true); bg.setLineGroupVisible(true); bg.setWakeVisible(true); - } } break; } diff --git a/src/main/java/seng302/models/BoatGroup.java b/src/main/java/seng302/models/BoatGroup.java index 57dd48db..54cb5e8c 100644 --- a/src/main/java/seng302/models/BoatGroup.java +++ b/src/main/java/seng302/models/BoatGroup.java @@ -19,7 +19,7 @@ import java.util.List; * UpdatePosition is called unless the window is minimized in which case it attempts to store animations and apply them * when the window is maximised. */ -public class BoatGroup extends RaceObject{ +public class BoatGroup extends Group{ //Constants for drawing private static final double TEAMNAME_X_OFFSET = 10d; @@ -32,6 +32,12 @@ public class BoatGroup extends RaceObject{ private Point2D lastPoint; private int wakeGenerationDelay = 10; private double distanceTravelled; + private double pixelVelocityX; + private double pixelVelocityY; + private double currentRotation; + private double rotationalGoal; + private double rotationalVelocity; + private static final int expectedUpdateInterval = 200; //Graphical objects private Yacht boat; private Group lineGroup = new Group(); @@ -194,7 +200,7 @@ public class BoatGroup extends RaceObject{ * @param rotation Rotation to move graphics to. * @param raceIds RaceID of the object to move. */ - public void setDestination (double newXValue, double newYValue, double rotation, double groundSpeed, int... raceIds) { + public void setDestination (double newXValue, double newYValue, double rotation, double groundSpeed, int raceIds) { if (hasRaceId(raceIds)) { if (setToInitialLocation) { destinationSet = true; @@ -254,7 +260,7 @@ public class BoatGroup extends RaceObject{ } } - public void setDestination (double newXValue, double newYValue, double groundSpeed, int... raceIDs) { + public void setDestination (double newXValue, double newYValue, double groundSpeed, int raceIDs) { destinationSet = true; if (hasRaceId(raceIDs)) { @@ -318,8 +324,8 @@ public class BoatGroup extends RaceObject{ * * @return An array containing all ID's associated with this RaceObject. */ - public int[] getRaceIds () { - return new int[] {boat.getSourceID()}; + public int getRaceId() { + return boat.getSourceID(); } /** @@ -355,4 +361,24 @@ public class BoatGroup extends RaceObject{ } }); } + + /** + * Calculates the rotational velocity required to reach the rotationalGoal from the currentRotation. + */ + protected void calculateRotationalVelocity () { + if (Math.abs(rotationalGoal - currentRotation) > 180) { + if (rotationalGoal - currentRotation >= 0) { + this.rotationalVelocity = ((rotationalGoal - currentRotation) - 360) / expectedUpdateInterval; + } else { + this.rotationalVelocity = (360 + (rotationalGoal - currentRotation)) / expectedUpdateInterval; + } + } else { + this.rotationalVelocity = (rotationalGoal - currentRotation) / expectedUpdateInterval; + } + //Sometimes the rotation is too large to be realistic. In that case just do it instantly. + if (Math.abs(rotationalVelocity) > 1) { + rotationalVelocity = 0; + rotateTo(rotationalGoal); + } + } } diff --git a/src/main/java/seng302/models/RaceObject.java b/src/main/java/seng302/models/RaceObject.java deleted file mode 100644 index 91f02971..00000000 --- a/src/main/java/seng302/models/RaceObject.java +++ /dev/null @@ -1,87 +0,0 @@ -package seng302.models; - -import javafx.geometry.Point2D; -import javafx.scene.Group; - -/** - * RaceObject defines the behaviour that animated objects whose position is updated from a yacht race data stream must - * adhere to. - */ -public abstract class RaceObject extends Group { - - //Time between sections of race - protected static double expectedUpdateInterval = 200; - - protected double rotationalGoal; - protected double currentRotation; - protected double rotationalVelocity; - protected double pixelVelocityX; - protected double pixelVelocityY; - - public Point2D getPosition () { - return new Point2D(super.getLayoutX(), getLayoutY()); - } - - public static double getExpectedUpdateInterval() { - return expectedUpdateInterval; - } - - /** - * - */ - public static void setExpectedUpdateInterval(double expectedUpdateInterval) { - RaceObject.expectedUpdateInterval = expectedUpdateInterval; - } - - /** - * Calculates the rotational velocity required to reach the rotationalGoal from the currentRotation. - */ - protected void calculateRotationalVelocity () { - if (Math.abs(rotationalGoal - currentRotation) > 180) { - if (rotationalGoal - currentRotation >= 0) { - this.rotationalVelocity = ((rotationalGoal - currentRotation) - 360) / expectedUpdateInterval; - } else { - this.rotationalVelocity = (360 + (rotationalGoal - currentRotation)) / expectedUpdateInterval; - } - } else { - this.rotationalVelocity = (rotationalGoal - currentRotation) / expectedUpdateInterval; - } - //Sometimes the rotation is too large to be realistic. In that case just do it instantly. - if (Math.abs(rotationalVelocity) > 1) { - rotationalVelocity = 0; - rotateTo(rotationalGoal); - } - } - - /** - * Sets the destination of everything within the RaceObject that has an ID in the array raceIds. The destination is - * set to the co-ordinates (x, y) with the given rotation. - * @param x X co-ordinate to move the graphics to. - * @param y Y co-ordinate to move the graphics to. - * @param rotation Rotation to move graphics to. - * @param raceIds RaceID of the object to move. - */ - public abstract void setDestination (double x, double y, double rotation, double groundSpeed, int... raceIds); - /** - * Sets the destination of everything within the RaceObject that has an ID in the array raceIds. The destination is - * set to the co-ordinates (x, y). - * @param x X co-ordinate to move the graphic to. - * @param y Y co-ordinate to move the graphic to. - * @param raceIds RaceID to the object to move. - */ - public abstract void setDestination (double x, double y, double groundSpeed, int... raceIds); - - public abstract void updatePosition (long timeInterval); - - public abstract void moveTo (double x, double y, double rotation); - - public abstract void moveTo (double x, double y); - - public abstract void moveGroupBy(double x, double y, double rotation); - - public abstract void rotateTo (double rotation); - - public abstract boolean hasRaceId (int... raceIds); - - public abstract int[] getRaceIds (); -} diff --git a/src/main/java/seng302/models/mark/MarkGroup.java b/src/main/java/seng302/models/mark/MarkGroup.java index 78a97d58..22fe05d8 100644 --- a/src/main/java/seng302/models/mark/MarkGroup.java +++ b/src/main/java/seng302/models/mark/MarkGroup.java @@ -1,12 +1,11 @@ package seng302.models.mark; import javafx.geometry.Point2D; -import javafx.scene.Node; +import javafx.scene.Group; import javafx.scene.paint.Color; import javafx.scene.shape.Circle; import javafx.scene.shape.Line; import javafx.scene.transform.Rotate; -import seng302.models.RaceObject; import java.util.ArrayList; import java.util.List; @@ -14,7 +13,7 @@ import java.util.List; /** * Created by CJIRWIN on 26/04/2017. */ -public class MarkGroup extends RaceObject { +public class MarkGroup extends Group { private static int MARK_RADIUS = 5; private static int LINE_THICKNESS = 2; @@ -23,14 +22,8 @@ public class MarkGroup extends RaceObject { private List marks = new ArrayList<>(); private Mark mainMark; - private double[] nodePixelVelocitiesX; - private double[] nodePixelVelocitiesY; - private Point2D[] nodeDestinations; public MarkGroup (Mark mark, Point2D... points) { - nodePixelVelocitiesX = new double[points.length]; - nodePixelVelocitiesY = new double[points.length]; - nodeDestinations = new Point2D[points.length]; marks.add(mark); mainMark = mark; Color color = Color.BLACK; @@ -47,25 +40,14 @@ public class MarkGroup extends RaceObject { MARK_RADIUS, color ); - nodeDestinations = new Point2D[]{ - new Point2D(markCircle.getCenterX(), markCircle.getCenterY() - ) - }; super.getChildren().add(markCircle); } else { -// marks.add(((GateMark) mark).getSingleMark1()); -// marks.add(((GateMark) mark).getSingleMark2()); - nodePixelVelocitiesX = new double[]{0d,0d}; - nodePixelVelocitiesY = new double[]{0d,0d}; - nodeDestinations = new Point2D[2]; - markCircle = new Circle( points[0].getX(), points[0].getY(), MARK_RADIUS, color ); - nodeDestinations[0] = new Point2D(markCircle.getCenterX(), markCircle.getCenterY()); super.getChildren().add(markCircle); markCircle = new Circle( @@ -74,7 +56,6 @@ public class MarkGroup extends RaceObject { MARK_RADIUS, color ); - nodeDestinations[1] = new Point2D(markCircle.getCenterX(), markCircle.getCenterY()); super.getChildren().add(markCircle); Line line = new Line( points[0].getX(), @@ -91,117 +72,27 @@ public class MarkGroup extends RaceObject { } } - public void setDestination (double x, double y, double rotation, double groundSpeed, int... raceIds) { - setDestination(x, y, 0, raceIds); - this.rotationalGoal = rotation; - calculateRotationalVelocity(); - } - - public void setDestination (double x, double y, double groundSpeed, int... raceIds) { - for (int i = 0; i < marks.size(); i++) - for (int id : raceIds) - if (id == marks.get(i).getId()) - setDestinationChild(x, y, 0, Math.max(0, i-1)); - } - - - private void setDestinationChild (double x, double y, double speed, int childIndex) { - //double relativeX = x - super.getLayoutX(); - //double relativeY = y - super.getLayoutY(); - Circle markCircle = (Circle) super.getChildren().get(childIndex); - this.nodeDestinations[childIndex] = new Point2D(x, y); - //if (Math.abs(relativeX - markCircle.getCenterX()) > 30 && Math.abs(relativeY - markCircle.getCenterY()) > 30) { - this.nodePixelVelocitiesX[childIndex] = (x - markCircle.getCenterX()) / expectedUpdateInterval; - this.nodePixelVelocitiesY[childIndex] = (y - markCircle.getCenterY()) / expectedUpdateInterval; - //} - } - - public void rotateTo (double rotation) { - if (mainMark.getMarkType() != MarkType.SINGLE_MARK) { - Line line = (Line) super.getChildren().get(2); - double xCenter = Math.abs(line.getEndX() - line.getStartX()); - double yCenter = Math.abs(line.getEndY() - line.getStartY()); - super.getTransforms().setAll(new Rotate(rotation, xCenter, yCenter)); - } - } - - public void updatePosition (long timeInterval) { - Circle markCircle = (Circle) super.getChildren().get(0); - - if (nodePixelVelocitiesX[0] > 0 && markCircle.getCenterX() > nodeDestinations[0].getX() || - nodePixelVelocitiesX[0] < 0 && markCircle.getCenterX() < nodeDestinations[0].getY()) - nodePixelVelocitiesX[0] = 0; - else if (nodePixelVelocitiesX[0] != 0) - markCircle.setCenterX(markCircle.getCenterX() + nodePixelVelocitiesX[0] * timeInterval); - - if (nodePixelVelocitiesY[0] > 0 && markCircle.getCenterY() > nodeDestinations[0].getY() || - nodePixelVelocitiesY[0] < 0 && markCircle.getCenterY() < nodeDestinations[0].getY()) - nodePixelVelocitiesY[0] = 0; - else if (nodePixelVelocitiesY[0] != 0) - markCircle.setCenterY(markCircle.getCenterY() + nodePixelVelocitiesY[0] * timeInterval); - - if (mainMark.getMarkType() != MarkType.SINGLE_MARK) { - - Line line = (Line) super.getChildren().get(2); - line.setStartX(markCircle.getCenterX()); - line.setStartY(markCircle.getCenterY()); - - markCircle = (Circle) super.getChildren().get(1); - - if (nodePixelVelocitiesX[1] > 0 && markCircle.getCenterX() >= nodeDestinations[1].getX() || - nodePixelVelocitiesX[1] < 0 && markCircle.getCenterX() <= nodeDestinations[1].getX()) - nodePixelVelocitiesX[1] = 0; - else if (nodePixelVelocitiesX[1] != 0) - markCircle.setCenterX(markCircle.getCenterX() + nodePixelVelocitiesX[1] * timeInterval); - - if (nodePixelVelocitiesY[1] > 0 && markCircle.getCenterY() > nodeDestinations[1].getY() || - nodePixelVelocitiesY[1] < 0 && markCircle.getCenterY() < nodeDestinations[1].getY()) - nodePixelVelocitiesY[1] = 0; - else if (nodePixelVelocitiesY[1] != 0) - markCircle.setCenterY(markCircle.getCenterY() + nodePixelVelocitiesY[1] * timeInterval); - line.setEndX(markCircle.getCenterX()); - line.setEndY(markCircle.getCenterY()); - } - } - - public void moveGroupBy (double x, double y, double rotation) { - if (mainMark.getMarkType() != MarkType.SINGLE_MARK) { - Line line = (Line) super.getChildren().get(2); - for (int childIndex = 0; childIndex < 2; childIndex++){ - Circle mark = (Circle) super.getChildren().get(childIndex); - mark.setCenterY(mark.getCenterY() + y); - mark.setCenterX(mark.getCenterX() + x); - } - line.setStartX(line.getStartX() + x); - line.setStartY(line.getStartY() + y); - line.setEndX(line.getEndX() + x); - line.setEndY(line.getEndY() + y); - } else { - Circle mark = (Circle) super.getChildren().get(0); - mark.setCenterY(mark.getCenterY() + y); - mark.setCenterX(mark.getCenterX() + x); - } - rotateTo(currentRotation + rotation); - } - - public void moveTo (double x, double y, double rotation) { - moveTo(x, y); - rotateTo(rotation); - } - - public void moveTo (double x, double y) { - Circle markCircle = (Circle) super.getChildren().get(0); - markCircle.setCenterX(x); - markCircle.setCenterY(y); - if (mainMark.getMarkType() != MarkType.SINGLE_MARK) { - markCircle = (Circle) super.getChildren().get(1); + public void moveMarkTo (double x, double y, int raceId) + { + if (mainMark.getMarkType() == MarkType.SINGLE_MARK) { + Circle markCircle = (Circle) super.getChildren().get(0); markCircle.setCenterX(x); markCircle.setCenterY(y); - Line line = (Line) super.getChildren().get(2); - line.setStartX(x); - line.setStartY(y); - line.setEndX(x); - line.setEndY(y); + } else { + Circle markCircle1 = (Circle) super.getChildren().get(0); + Circle markCircle2 = (Circle) super.getChildren().get(1); + Line connectingLine = (Line) super.getChildren().get(2); + if (marks.get(1).getId() == raceId) { + markCircle1.setCenterX(x); + markCircle1.setCenterY(y); + connectingLine.setStartX(markCircle1.getCenterX()); + connectingLine.setStartY(markCircle1.getCenterY()); + } else if (marks.get(2).getId() == raceId) { + markCircle2.setCenterX(x); + markCircle2.setCenterY(y); + connectingLine.setEndX(markCircle2.getCenterX()); + connectingLine.setEndY(markCircle2.getCenterY()); + } } } @@ -213,14 +104,6 @@ public class MarkGroup extends RaceObject { return false; } - public static int getMarkRadius() { - return MARK_RADIUS; - } - - public static void setMarkRadius(int markRadius) { - MARK_RADIUS = markRadius; - } - public int[] getRaceIds () { int[] idArray = new int[marks.size()]; int i = 0; From 23bc643c91e431361958440fbff1d808e96f5d8b Mon Sep 17 00:00:00 2001 From: Calum Date: Mon, 15 May 2017 15:20:21 +1200 Subject: [PATCH 09/32] Removed some unused functions and imports caused by code refactor. #chore --- src/main/java/seng302/models/BoatGroup.java | 20 ------------------- .../java/seng302/models/mark/MarkGroup.java | 1 - 2 files changed, 21 deletions(-) diff --git a/src/main/java/seng302/models/BoatGroup.java b/src/main/java/seng302/models/BoatGroup.java index 54cb5e8c..45b707e1 100644 --- a/src/main/java/seng302/models/BoatGroup.java +++ b/src/main/java/seng302/models/BoatGroup.java @@ -260,31 +260,11 @@ public class BoatGroup extends Group{ } } - public void setDestination (double newXValue, double newYValue, double groundSpeed, int raceIDs) { - destinationSet = true; - - if (hasRaceId(raceIDs)) { - double rotation = Math.abs( - Math.toDegrees( - Math.atan( - (newYValue - boatPoly.getLayoutY()) / (newXValue - boatPoly.getLayoutX()) - ) - ) - ); - setDestination(newXValue, newYValue, rotation, groundSpeed, raceIDs); - } - } - public void rotateTo (double rotation) { currentRotation = rotation; boatPoly.getTransforms().setAll(new Rotate(rotation)); } - public void forceRotation () { - rotateTo (rotationalGoal); - wake.rotate(rotationalGoal); - } - public void setTeamNameObjectVisible(Boolean visible) { teamNameObject.setVisible(visible); } diff --git a/src/main/java/seng302/models/mark/MarkGroup.java b/src/main/java/seng302/models/mark/MarkGroup.java index 22fe05d8..b428c5ed 100644 --- a/src/main/java/seng302/models/mark/MarkGroup.java +++ b/src/main/java/seng302/models/mark/MarkGroup.java @@ -5,7 +5,6 @@ import javafx.scene.Group; import javafx.scene.paint.Color; import javafx.scene.shape.Circle; import javafx.scene.shape.Line; -import javafx.scene.transform.Rotate; import java.util.ArrayList; import java.util.List; From ed8d70c3b3e0fcb3e09b490d6c594f69531d58f6 Mon Sep 17 00:00:00 2001 From: Peter Galloway Date: Mon, 15 May 2017 17:53:11 +1200 Subject: [PATCH 10/32] commented out buffered code and cleaned up some other areas to try and make the boatgroup clear enough to modify #story[923] --- .../seng302/controllers/CanvasController.java | 81 +++++++++---------- src/main/java/seng302/models/BoatGroup.java | 48 ++--------- src/main/java/seng302/models/RaceObject.java | 20 +---- .../java/seng302/models/mark/MarkGroup.java | 8 +- .../seng302/models/parsers/StreamPacket.java | 44 ---------- .../seng302/models/parsers/StreamParser.java | 24 +++--- .../models/parsers/StreamReceiverTest.java | 1 + 7 files changed, 61 insertions(+), 165 deletions(-) delete mode 100644 src/main/java/seng302/models/parsers/StreamPacket.java diff --git a/src/main/java/seng302/controllers/CanvasController.java b/src/main/java/seng302/controllers/CanvasController.java index 4d57559b..37f45f1a 100644 --- a/src/main/java/seng302/controllers/CanvasController.java +++ b/src/main/java/seng302/controllers/CanvasController.java @@ -106,7 +106,7 @@ public class CanvasController { // TODO: 1/05/17 wmu16 - Change this call to now draw the marks as from the xml - drawBoats(); + initializeBoats(); timer = new AnimationTimer() { @Override @@ -157,8 +157,8 @@ public class CanvasController { SingleMark thisMark1 = new SingleMark("", thisPoint1.getLat(), thisPoint1.getLng(), thisPoint1.getSeqID()); Limit thisPoint2 = courseLimits.get(i+1); SingleMark thisMark2 = new SingleMark("", thisPoint2.getLat(), thisPoint2.getLng(), thisPoint2.getSeqID()); - Point2D borderPoint1 = findScaledXY(thisMark1); - Point2D borderPoint2 = findScaledXY(thisMark2); + Point2D borderPoint1 = latLonToXY(thisMark1.getLatitude(), thisMark1.getLongitude()); + Point2D borderPoint2 = latLonToXY(thisMark2.getLatitude(), thisMark2.getLongitude()); gc.strokeLine(borderPoint1.getX(), borderPoint1.getY(), borderPoint2.getX(), borderPoint2.getY()); xBoundaryPoints[i] = borderPoint1.getX(); @@ -168,8 +168,8 @@ public class CanvasController { SingleMark thisMark1 = new SingleMark("", thisPoint1.getLat(), thisPoint1.getLng(), thisPoint1.getSeqID()); Limit thisPoint2 = courseLimits.get(0); SingleMark thisMark2 = new SingleMark("", thisPoint2.getLat(), thisPoint2.getLng(), thisPoint2.getSeqID()); - Point2D borderPoint1 = findScaledXY(thisMark1); - Point2D borderPoint2 = findScaledXY(thisMark2); + Point2D borderPoint1 = latLonToXY(thisMark1.getLatitude(), thisMark1.getLongitude()); + Point2D borderPoint2 = latLonToXY(thisMark2.getLatitude(), thisMark2.getLongitude()); gc.strokeLine(borderPoint1.getX(), borderPoint1.getY(), borderPoint2.getX(), borderPoint2.getY()); xBoundaryPoints[courseLimits.size()-1] = borderPoint1.getX(); @@ -207,8 +207,8 @@ public class CanvasController { singleMark1.getLongitude()); markGroup = new MarkGroup(thisGateMark, - findScaledXY(thisGateMark.getSingleMark1()), - findScaledXY(thisGateMark.getSingleMark2())); + latLonToXY(thisGateMark.getSingleMark1().getLatitude(), thisGateMark.getSingleMark1().getLongitude()), + latLonToXY(thisGateMark.getSingleMark2().getLatitude(), thisGateMark.getSingleMark2().getLongitude())); raceObjects.add(markGroup); raceMarks.add(thisGateMark); @@ -221,7 +221,7 @@ public class CanvasController { singleMark.getTargetLng(), singleMark.getSourceID()); - markGroup = new MarkGroup(thisSingleMark, findScaledXY(thisSingleMark)); + markGroup = new MarkGroup(thisSingleMark, latLonToXY(thisSingleMark.getLatitude(), thisSingleMark.getLongitude())); raceObjects.add(markGroup); raceMarks.add(thisSingleMark); @@ -245,27 +245,30 @@ public class CanvasController { private void move(long id, RaceObject raceObject){ PriorityBlockingQueue movementQueue = StreamParser.boatPositions.get(id); if (movementQueue.size() > 0){ - BoatPositionPacket positionPacket = movementQueue.peek(); +// BoatPositionPacket positionPacket = movementQueue.peek(); //this code adds a delay to reading from the movementQueue //in case things being put into the movement queue are slightly //out of order - int delayTime = 1000; - int loopTime = delayTime * 10; - long timeDiff = (System.currentTimeMillis()%loopTime - positionPacket.getTimeValid()%loopTime); - if (timeDiff < 0){ - timeDiff = loopTime + timeDiff; - } - if (timeDiff > delayTime) { - try { - positionPacket = movementQueue.take(); - Point2D p2d = latLonToXY(positionPacket.getLat(), positionPacket.getLon()); - double heading = 360.0 / 0xffff * positionPacket.getHeading(); - raceObject.setDestination(p2d.getX(), p2d.getY(), heading, positionPacket.getGroundSpeed(), (int) id); - } catch (InterruptedException e){ - e.printStackTrace(); +// int delayTime = 1000; +// int loopTime = delayTime * 10; +// long timeDiff = (System.currentTimeMillis()%loopTime - positionPacket.getTimeValid()%loopTime); +// if (timeDiff < 0){ +// timeDiff = loopTime + timeDiff; +// } +// if (timeDiff > delayTime) { + try { + BoatPositionPacket positionPacket = movementQueue.take(); + if (id == 104){ + System.out.println(positionPacket.getTimeValid()); } + Point2D p2d = latLonToXY(positionPacket.getLat(), positionPacket.getLon()); + double heading = 360.0 / 0xffff * positionPacket.getHeading(); + raceObject.setDestination(p2d.getX(), p2d.getY(), heading, positionPacket.getGroundSpeed(), (int) id); + } catch (InterruptedException e){ + e.printStackTrace(); } +// } } } @@ -320,20 +323,13 @@ public class CanvasController { /** * Draws all the boats. */ - private void drawBoats() { -// Map timelineInfos = raceViewController.getTimelineInfos(); -// List boats = raceViewController.getStartingBoats(); + private void initializeBoats() { Map boats = StreamParser.getBoats(); - Double startingX = raceObjects.get(0).getLayoutX(); - Double startingY = raceObjects.get(0).getLayoutY(); Group boatAnnotations = new Group(); for (Yacht boat : boats.values()) { -// for (Boat boat : boats) { boat.setColour(Colors.getColor()); BoatGroup boatGroup = new BoatGroup(boat, boat.getColour()); - boatGroup.moveTo(startingX, startingY, 0d); - //boatGroup.setStage(raceViewController.getStage()); raceObjects.add(boatGroup); boatAnnotations.getChildren().add(boatGroup.getLowPriorityAnnotations()); } @@ -456,10 +452,12 @@ public class CanvasController { if (!processed.contains(mark)) { if (mark.getMarkType() != MarkType.SINGLE_MARK) { GateMark gateMark = (GateMark) mark; - markGroup = new MarkGroup(mark, findScaledXY(gateMark.getSingleMark1()), findScaledXY(gateMark.getSingleMark2())); + markGroup = new MarkGroup(mark, + latLonToXY(gateMark.getSingleMark1().getLatitude(), gateMark.getSingleMark1().getLongitude()), + latLonToXY(gateMark.getSingleMark2().getLatitude(), gateMark.getSingleMark2().getLongitude())); raceObjects.add(markGroup); } else { - markGroup = new MarkGroup(mark, findScaledXY(mark)); + markGroup = new MarkGroup(mark, latLonToXY(mark.getLatitude(), mark.getLongitude())); raceObjects.add(markGroup); } processed.add(mark); @@ -467,19 +465,18 @@ public class CanvasController { } } - private Point2D findScaledXY (Mark unscaled) { - return findScaledXY (minLatPoint.getLatitude(), minLatPoint.getLongitude(), - unscaled.getLatitude(), unscaled.getLongitude()); - } - private Point2D findScaledXY (double latA, double lonA, double latB, double lonB) { + + private Point2D latLonToXY (double latitude, double longitude){ double distanceFromReference; double angleFromReference; int xAxisLocation = (int) referencePointX; int yAxisLocation = (int) referencePointY; - angleFromReference = Mark.calculateHeadingRad(latA, lonA, latB, lonB); - distanceFromReference = Mark.calculateDistance(latA, lonA, latB, lonB); + double minLat = minLatPoint.getLatitude(); + double minLon = minLatPoint.getLongitude(); + angleFromReference = Mark.calculateHeadingRad(minLat, minLon, latitude, longitude); + distanceFromReference = Mark.calculateDistance(minLat, minLon, latitude, longitude); if (angleFromReference >= 0 && angleFromReference <= Math.PI / 2) { xAxisLocation += (int) Math.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference); yAxisLocation -= (int) Math.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference); @@ -529,10 +526,6 @@ public class CanvasController { } } - private Point2D latLonToXY (double latitude, double longitude) { - return findScaledXY(minLatPoint.getLatitude(), minLatPoint.getLongitude(), latitude, longitude); - } - List getRaceObjects() { return raceObjects; } diff --git a/src/main/java/seng302/models/BoatGroup.java b/src/main/java/seng302/models/BoatGroup.java index 57dd48db..327ae1ba 100644 --- a/src/main/java/seng302/models/BoatGroup.java +++ b/src/main/java/seng302/models/BoatGroup.java @@ -122,7 +122,8 @@ public class BoatGroup extends RaceObject{ velocityObject.setLayoutY(velocityObject.getLayoutY() + dy); wake.setLayoutX(wake.getLayoutX() + dx); wake.setLayoutY(wake.getLayoutY() + dy); - rotateTo(rotation + currentRotation); + currentRotation = rotation + currentRotation; + boatPoly.getTransforms().setAll(new Rotate(rotation)); } /** @@ -132,16 +133,8 @@ public class BoatGroup extends RaceObject{ * @param rotation The heading in degrees from north the boat should rotate to. */ public void moveTo (double x, double y, double rotation) { - rotateTo(rotation); - moveTo(x, y); - } - - /** - * Moves the boat and its children annotations to coordinates specified - * @param x The X coordinate to move the boat to - * @param y The Y coordinate to move the boat to - */ - public void moveTo (double x, double y) { + currentRotation = rotation; + boatPoly.getTransforms().setAll(new Rotate(rotation)); boatPoly.setLayoutX(x); boatPoly.setLayoutY(y); teamNameObject.setLayoutX(x); @@ -165,6 +158,7 @@ public class BoatGroup extends RaceObject{ double rotation = rotationalVelocity * timeInterval; distanceTravelled += Math.abs(dx) + Math.abs(dy); moveGroupBy(dx, dy, rotation); + //Draw a new section of the trail every 20 pixels of movement. if (distanceTravelled > 20) { distanceTravelled = 0; @@ -203,12 +197,6 @@ public class BoatGroup extends RaceObject{ currentRotation = 360 - currentRotation; double dx = newXValue - boatPoly.getLayoutX(); double dy = newYValue - boatPoly.getLayoutY(); - //Check movement is reasonable. Assumes a 1000 * 1000 canvas - if (Math.abs(dx) > 50 || Math.abs(dy) > 50) { - dx = 0; - dy = 0; - moveTo(newXValue, newYValue); - } pixelVelocityX = dx / expectedUpdateInterval; pixelVelocityY = dy / expectedUpdateInterval; @@ -217,7 +205,6 @@ public class BoatGroup extends RaceObject{ if (wakeGenerationDelay > 0) { wake.rotate(rotationalGoal); - rotateTo(rotationalGoal); //Need to test with this removed. rotationalVelocity = 0; wakeGenerationDelay--; } else { @@ -254,31 +241,6 @@ public class BoatGroup extends RaceObject{ } } - public void setDestination (double newXValue, double newYValue, double groundSpeed, int... raceIDs) { - destinationSet = true; - - if (hasRaceId(raceIDs)) { - double rotation = Math.abs( - Math.toDegrees( - Math.atan( - (newYValue - boatPoly.getLayoutY()) / (newXValue - boatPoly.getLayoutX()) - ) - ) - ); - setDestination(newXValue, newYValue, rotation, groundSpeed, raceIDs); - } - } - - public void rotateTo (double rotation) { - currentRotation = rotation; - boatPoly.getTransforms().setAll(new Rotate(rotation)); - } - - public void forceRotation () { - rotateTo (rotationalGoal); - wake.rotate(rotationalGoal); - } - public void setTeamNameObjectVisible(Boolean visible) { teamNameObject.setVisible(visible); } diff --git a/src/main/java/seng302/models/RaceObject.java b/src/main/java/seng302/models/RaceObject.java index 91f02971..706bfd48 100644 --- a/src/main/java/seng302/models/RaceObject.java +++ b/src/main/java/seng302/models/RaceObject.java @@ -47,10 +47,10 @@ public abstract class RaceObject extends Group { this.rotationalVelocity = (rotationalGoal - currentRotation) / expectedUpdateInterval; } //Sometimes the rotation is too large to be realistic. In that case just do it instantly. - if (Math.abs(rotationalVelocity) > 1) { - rotationalVelocity = 0; - rotateTo(rotationalGoal); - } +// if (Math.abs(rotationalVelocity) > 1) { +// rotationalVelocity = 0; +// rotateTo(rotationalGoal); +// } } /** @@ -62,25 +62,13 @@ public abstract class RaceObject extends Group { * @param raceIds RaceID of the object to move. */ public abstract void setDestination (double x, double y, double rotation, double groundSpeed, int... raceIds); - /** - * Sets the destination of everything within the RaceObject that has an ID in the array raceIds. The destination is - * set to the co-ordinates (x, y). - * @param x X co-ordinate to move the graphic to. - * @param y Y co-ordinate to move the graphic to. - * @param raceIds RaceID to the object to move. - */ - public abstract void setDestination (double x, double y, double groundSpeed, int... raceIds); public abstract void updatePosition (long timeInterval); public abstract void moveTo (double x, double y, double rotation); - public abstract void moveTo (double x, double y); - public abstract void moveGroupBy(double x, double y, double rotation); - public abstract void rotateTo (double rotation); - public abstract boolean hasRaceId (int... raceIds); public abstract int[] getRaceIds (); diff --git a/src/main/java/seng302/models/mark/MarkGroup.java b/src/main/java/seng302/models/mark/MarkGroup.java index 29931e01..6bcd40f4 100644 --- a/src/main/java/seng302/models/mark/MarkGroup.java +++ b/src/main/java/seng302/models/mark/MarkGroup.java @@ -92,16 +92,12 @@ public class MarkGroup extends RaceObject { } public void setDestination (double x, double y, double rotation, double groundSpeed, int... raceIds) { - setDestination(x, y, 0, raceIds); - this.rotationalGoal = rotation; - calculateRotationalVelocity(); - } - - public void setDestination (double x, double y, double groundSpeed, int... raceIds) { for (int i = 0; i < marks.size(); i++) for (int id : raceIds) if (id == marks.get(i).getId()) setDestinationChild(x, y, 0, Math.max(0, i-1)); + this.rotationalGoal = rotation; + calculateRotationalVelocity(); } diff --git a/src/main/java/seng302/models/parsers/StreamPacket.java b/src/main/java/seng302/models/parsers/StreamPacket.java deleted file mode 100644 index 5c2c0706..00000000 --- a/src/main/java/seng302/models/parsers/StreamPacket.java +++ /dev/null @@ -1,44 +0,0 @@ -package seng302.models.parsers; - -/** - * Created by kre39 on 23/04/17. - */ -public class StreamPacket { - - //Change int to an ENUM for the type - private PacketType type; - - private long messageLength; - private long timeStamp; - private byte[] payload; - - StreamPacket(int type, long messageLength, long timeStamp, byte[] payload) { - this.type = PacketType.assignPacketType(type); - this.messageLength = messageLength; - this.timeStamp = timeStamp; - this.payload = payload; -// System.out.println("type = " + this.type.toString()); - //switch the packet type to deal with what ever specific packet you want to deal with -// if (this.type == PacketType.XML_MESSAGE){ -// //System.out.println("--------"); -// System.out.println(new String(payload)); -// //StreamParser.parsePacket(this); -// } - } - - PacketType getType() { - return type; - } - - public long getMessageLength() { - return messageLength; - } - - byte[] getPayload() { - return payload; - } - - long getTimeStamp() { - return timeStamp; - } -} diff --git a/src/main/java/seng302/models/parsers/StreamParser.java b/src/main/java/seng302/models/parsers/StreamParser.java index deea3184..890f37f6 100644 --- a/src/main/java/seng302/models/parsers/StreamParser.java +++ b/src/main/java/seng302/models/parsers/StreamParser.java @@ -66,20 +66,20 @@ public class StreamParser extends Thread{ Thread.sleep(1); } while (appRunning){ - StreamPacket packet = StreamReceiver.packetBuffer.peek(); +// StreamPacket packet = StreamReceiver.packetBuffer.peek(); //this code adds a delay to reading from the packetBuffer so //out of order packets have time to order themselves in the queue - int delayTime = 1000; - int loopTime = delayTime * 10; - long transitTime = (System.currentTimeMillis()%loopTime - packet.getTimeStamp()%loopTime); - if (transitTime < 0){ - transitTime = loopTime + transitTime; - } - if (transitTime < delayTime) { - long sleepTime = delayTime - (transitTime); - Thread.sleep(sleepTime); - } - packet = StreamReceiver.packetBuffer.take(); +// int delayTime = 1000; +// int loopTime = delayTime * 10; +// long transitTime = (System.currentTimeMillis()%loopTime - packet.getTimeStamp()%loopTime); +// if (transitTime < 0){ +// transitTime = loopTime + transitTime; +// } +// if (transitTime < delayTime) { +// long sleepTime = delayTime - (transitTime); +// Thread.sleep(sleepTime); +// } + StreamPacket packet = StreamReceiver.packetBuffer.take(); parsePacket(packet); Thread.sleep(1); while (StreamReceiver.packetBuffer.peek() == null) { diff --git a/src/test/java/seng302/models/parsers/StreamReceiverTest.java b/src/test/java/seng302/models/parsers/StreamReceiverTest.java index c7951e3b..d2dc6b82 100644 --- a/src/test/java/seng302/models/parsers/StreamReceiverTest.java +++ b/src/test/java/seng302/models/parsers/StreamReceiverTest.java @@ -2,6 +2,7 @@ package seng302.models.parsers; import org.junit.Before; import org.junit.Test; +import seng302.models.parsers.packets.StreamPacket; import java.io.*; import java.lang.reflect.Method; From 9e3036e13460856b719f6010659bc48e65008057 Mon Sep 17 00:00:00 2001 From: Peter Galloway Date: Mon, 15 May 2017 23:17:36 +1200 Subject: [PATCH 11/32] Stripped down the boatgroup to the basic movement components and then tried to adjust how position updates are being dealt with to make everything more logically understandable. I made some progress in terms of understanding but the position update is still not as reliable as I would like. I will be explaining to other team members how this part of the code is working so the time I have spent is not completely wasted #story[923] --- .../seng302/controllers/CanvasController.java | 152 ++++---- .../java/seng302/controllers/Controller.java | 3 +- .../controllers/RaceViewController.java | 334 +++++------------- src/main/java/seng302/models/BoatGroup.java | 193 +++------- .../java/seng302/models/mark/MarkGroup.java | 193 +++------- .../seng302/models/stream/StreamParser.java | 13 +- .../models/stream/StreamReceiverTest.java | 2 +- 7 files changed, 250 insertions(+), 640 deletions(-) diff --git a/src/main/java/seng302/controllers/CanvasController.java b/src/main/java/seng302/controllers/CanvasController.java index a46c3481..c1a642fc 100644 --- a/src/main/java/seng302/controllers/CanvasController.java +++ b/src/main/java/seng302/controllers/CanvasController.java @@ -10,24 +10,13 @@ import javafx.scene.canvas.GraphicsContext; import javafx.scene.layout.AnchorPane; import javafx.scene.paint.Color; import javafx.scene.text.Font; -import seng302.models.BoatGroup; -import seng302.models.Colors; -import seng302.models.RaceObject; -import seng302.models.Yacht; import seng302.models.*; import seng302.models.mark.*; -import seng302.models.parsers.StreamParser; -import seng302.models.parsers.XMLParser; -import seng302.models.parsers.XMLParser.RaceXMLObject.CompoundMark; -import seng302.models.parsers.XMLParser.RaceXMLObject.Limit; -import seng302.models.parsers.packets.BoatPositionPacket; import seng302.models.stream.StreamParser; import seng302.models.stream.packets.BoatPositionPacket; import seng302.models.stream.XMLParser; import seng302.models.stream.XMLParser.RaceXMLObject.Limit; import seng302.models.mark.Mark; - -import java.text.DecimalFormat; import java.util.*; import java.util.concurrent.PriorityBlockingQueue; @@ -62,16 +51,13 @@ public class CanvasController { private Mark maxLonPoint; private double referencePointX; private double referencePointY; - private List raceObjects = new ArrayList<>(); - private List raceMarks = new ArrayList<>(); + private List markGroups = new ArrayList<>(); + private List boatGroups = new ArrayList<>(); //FRAME RATE - private static final double UPDATE_TIME = 0.016666; // 1 / 60 ie 60fps private final long[] frameTimes = new long[30]; private int frameTimeIndex = 0; private boolean arrayFilled = false; - private DecimalFormat decimalFormat2dp = new DecimalFormat("0.00"); - private double lastPacketTime = 0; public AnimationTimer timer; @@ -94,8 +80,6 @@ public class CanvasController { // Bind canvas size to stack pane size. canvas.widthProperty().bind(new SimpleDoubleProperty(CANVAS_WIDTH)); canvas.heightProperty().bind(new SimpleDoubleProperty(CANVAS_HEIGHT)); - //group.minWidth(CANVAS_WIDTH); - //group.minHeight(CANVAS_HEIGHT); } public void initializeCanvas (){ @@ -109,7 +93,7 @@ public class CanvasController { // TODO: 1/05/17 wmu16 - Change this call to now draw the marks as from the xml - initializeBoats(); + drawBoats(); timer = new AnimationTimer() { @Override @@ -132,7 +116,7 @@ public class CanvasController { // TODO: 1/05/17 cir27 - Make the RaceObjects update on the actual delay. elapsedNanos = 1000 / 60; - updateRaceObjects(); + updateGroups(); if (StreamParser.isRaceFinished()) { this.stop(); } @@ -160,10 +144,10 @@ public class CanvasController { SingleMark thisMark1 = new SingleMark("", thisPoint1.getLat(), thisPoint1.getLng(), thisPoint1.getSeqID()); Limit thisPoint2 = courseLimits.get(i+1); SingleMark thisMark2 = new SingleMark("", thisPoint2.getLat(), thisPoint2.getLng(), thisPoint2.getSeqID()); - Point2D borderPoint1 = latLonToXY(thisMark1.getLatitude(), thisMark1.getLongitude()); - Point2D borderPoint2 = latLonToXY(thisMark2.getLatitude(), thisMark2.getLongitude()); + Point2D borderPoint1 = findScaledXY(thisMark1); + Point2D borderPoint2 = findScaledXY(thisMark2); gc.strokeLine(borderPoint1.getX(), borderPoint1.getY(), - borderPoint2.getX(), borderPoint2.getY()); + borderPoint2.getX(), borderPoint2.getY()); xBoundaryPoints[i] = borderPoint1.getX(); yBoundaryPoints[i] = borderPoint1.getY(); } @@ -171,52 +155,42 @@ public class CanvasController { SingleMark thisMark1 = new SingleMark("", thisPoint1.getLat(), thisPoint1.getLng(), thisPoint1.getSeqID()); Limit thisPoint2 = courseLimits.get(0); SingleMark thisMark2 = new SingleMark("", thisPoint2.getLat(), thisPoint2.getLng(), thisPoint2.getSeqID()); - Point2D borderPoint1 = latLonToXY(thisMark1.getLatitude(), thisMark1.getLongitude()); - Point2D borderPoint2 = latLonToXY(thisMark2.getLatitude(), thisMark2.getLongitude()); + Point2D borderPoint1 = findScaledXY(thisMark1); + Point2D borderPoint2 = findScaledXY(thisMark2); gc.strokeLine(borderPoint1.getX(), borderPoint1.getY(), - borderPoint2.getX(), borderPoint2.getY()); + borderPoint2.getX(), borderPoint2.getY()); xBoundaryPoints[courseLimits.size()-1] = borderPoint1.getX(); yBoundaryPoints[courseLimits.size()-1] = borderPoint1.getY(); gc.setFill(Color.LIGHTBLUE); gc.fillPolygon(xBoundaryPoints,yBoundaryPoints,yBoundaryPoints.length); } - private void updateRaceObjects(){ - for (RaceObject raceObject : raceObjects) { - raceObject.updatePosition(1000 / 60); - // some raceObjects will have multiply ID's (for instance gate marks) - for (long id : raceObject.getRaceIds()) { - //checking if the current "ID" has any updates associated with it + private void updateGroups(){ + for (BoatGroup boatGroup : boatGroups) { + boatGroup.updatePosition(); + // some raceObjects will have multiple ID's (for instance gate marks) + //checking if the current "ID" has any updates associated with it + if (StreamParser.boatPositions.containsKey(boatGroup.getRaceId())) { + moveBoatGroup(boatGroup); + } + } + for (MarkGroup markGroup : markGroups) { + for (int id : markGroup.getRaceIds()) { if (StreamParser.boatPositions.containsKey(id)) { - move(id, raceObject); + moveMarkGroup(id, markGroup); } } } } - private void move(long id, RaceObject raceObject){ - PriorityBlockingQueue movementQueue = StreamParser.boatPositions.get(id); + private void moveBoatGroup(BoatGroup boatGroup) { + PriorityBlockingQueue movementQueue = StreamParser.boatPositions.get(boatGroup.getRaceId()); if (movementQueue.size() > 0){ -// BoatPositionPacket positionPacket = movementQueue.peek(); -// -// //this code adds a delay to reading from the movementQueue -// //in case things being put into the movement queue are slightly -// //out of order -// int delayTime = 1000; -// int loopTime = delayTime * 10; -// long timeDiff = (System.currentTimeMillis()%loopTime - positionPacket.getTimeValid()%loopTime); -// if (timeDiff < 0){ -// timeDiff = loopTime + timeDiff; -// } -// if (timeDiff > delayTime) { try { BoatPositionPacket positionPacket = movementQueue.take(); - if (id == 104){ - System.out.println(positionPacket.getTimeValid()); - } - Point2D p2d = latLonToXY(positionPacket.getLat(), positionPacket.getLon()); + Point2D p2d = findScaledXY(positionPacket.getLat(), positionPacket.getLon()); double heading = 360.0 / 0xffff * positionPacket.getHeading(); - raceObject.setDestination(p2d.getX(), p2d.getY(), heading, positionPacket.getGroundSpeed(), (int) id); + boatGroup.setDestination(p2d.getX(), p2d.getY(), heading, positionPacket.getGroundSpeed(), boatGroup.getRaceId()); } catch (InterruptedException e){ e.printStackTrace(); } @@ -224,6 +198,19 @@ public class CanvasController { } } + void moveMarkGroup (int raceId, MarkGroup markGroup) { + PriorityBlockingQueue movementQueue = StreamParser.boatPositions.get(raceId); + if (movementQueue.size() > 0){ + try { + BoatPositionPacket positionPacket = movementQueue.take(); + Point2D p2d = findScaledXY(positionPacket.getLat(), positionPacket.getLon()); + markGroup.moveMarkTo(p2d.getX(), p2d.getY(), raceId); + } catch (InterruptedException e){ + e.printStackTrace(); + } + } + } + class ResizableCanvas extends Canvas { ResizableCanvas() { @@ -275,18 +262,18 @@ public class CanvasController { /** * Draws all the boats. */ - private void initializeBoats() { + private void drawBoats() { Map boats = StreamParser.getBoats(); Group boatAnnotations = new Group(); for (Yacht boat : boats.values()) { boat.setColour(Colors.getColor()); BoatGroup boatGroup = new BoatGroup(boat, boat.getColour()); - raceObjects.add(boatGroup); + boatGroups.add(boatGroup); boatAnnotations.getChildren().add(boatGroup.getLowPriorityAnnotations()); } group.getChildren().add(boatAnnotations); - group.getChildren().addAll(raceObjects); + group.getChildren().addAll(boatGroups); } /** @@ -362,6 +349,7 @@ public class CanvasController { } } + /** * Finds the scale factor necessary to fit all race markers within the onscreen map and assigns it to distanceScaleFactor * Returns the max horizontal distance of the map. @@ -395,36 +383,37 @@ public class CanvasController { * are scaled according to the distanceScaleFactor variable. */ private void givePointsXY() { - List allPoints = StreamParser.getXmlObject().getRaceXML().getCompoundMarks(); - List processed = new ArrayList<>(); - RaceObject markGroup; - - for (XMLParser.RaceXMLObject.CompoundMark mark : allPoints) { - if (!processed.contains(mark)) { - if (mark.getMarkType() != MarkType.SINGLE_MARK) { - markGroup = new MarkGroup(mark, findScaledXY(mark.getMarks().get(0)), findScaledXY(mark.getMarks().get(1))); - raceObjects.add(markGroup); - } else { - markGroup = new MarkGroup(mark, findScaledXY(mark.getMarks().get(0))); - raceObjects.add(markGroup); - } - processed.add(mark); - } - } +// List allPoints = StreamParser.getXmlObject().getRaceXML().getCompoundMarks(); +// List processed = new ArrayList<>(); +// MarkGroup markGroup; +// +// for (XMLParser.RaceXMLObject.CompoundMark mark : allPoints) { +// if (!processed.contains(mark)) { +// if (mark.getMarkType() != MarkType.SINGLE_MARK) { +// markGroup = new MarkGroup(mark, findScaledXY(mark.getMarks().get(0)), findScaledXY(mark.getMarks().get(1))); +// markGroups.add(markGroup); +// } else { +// markGroup = new MarkGroup(mark, findScaledXY(mark.getMarks().get(0))); +// markGroups.add(markGroup); +// } +// processed.add(mark); +// } +// } + group.getChildren().addAll(boatGroups); } + private Point2D findScaledXY (Mark unscaled) { + return findScaledXY (unscaled.getLatitude(), unscaled.getLongitude()); + } - - private Point2D latLonToXY (double latitude, double longitude){ + private Point2D findScaledXY (double unscaledLat, double unscaledLon) { double distanceFromReference; double angleFromReference; int xAxisLocation = (int) referencePointX; int yAxisLocation = (int) referencePointY; - double minLat = minLatPoint.getLatitude(); - double minLon = minLatPoint.getLongitude(); - angleFromReference = Mark.calculateHeadingRad(minLat, minLon, latitude, longitude); - distanceFromReference = Mark.calculateDistance(minLat, minLon, latitude, longitude); + angleFromReference = Mark.calculateHeadingRad(minLatPoint.getLatitude(), minLatPoint.getLongitude(), unscaledLat, unscaledLon); + distanceFromReference = Mark.calculateDistance(minLatPoint.getLatitude(), minLatPoint.getLongitude(), unscaledLat, unscaledLon); if (angleFromReference >= 0 && angleFromReference <= Math.PI / 2) { xAxisLocation += (int) Math.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference); yAxisLocation -= (int) Math.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference); @@ -444,12 +433,7 @@ public class CanvasController { return new Point2D(xAxisLocation, yAxisLocation); } - - private Point2D latLonToXY (double latitude, double longitude) { - return findScaledXY(minLatPoint.getLatitude(), minLatPoint.getLongitude(), latitude, longitude); - } - - List getRaceObjects() { - return raceObjects; + List getBoatGroups() { + return boatGroups; } } \ No newline at end of file diff --git a/src/main/java/seng302/controllers/Controller.java b/src/main/java/seng302/controllers/Controller.java index da85b3ae..bebc57fd 100644 --- a/src/main/java/seng302/controllers/Controller.java +++ b/src/main/java/seng302/controllers/Controller.java @@ -15,14 +15,13 @@ import javafx.scene.layout.AnchorPane; import javafx.scene.layout.Pane; import javafx.scene.paint.Color; import seng302.models.Yacht; -import seng302.models.parsers.StreamParser; -import seng302.models.parsers.XMLParser; import java.io.IOException; import java.net.URL; import java.util.ResourceBundle; import java.util.Timer; import java.util.TimerTask; +import seng302.models.stream.StreamParser; public class Controller implements Initializable { @FXML diff --git a/src/main/java/seng302/controllers/RaceViewController.java b/src/main/java/seng302/controllers/RaceViewController.java index 24ff0163..8a09619e 100644 --- a/src/main/java/seng302/controllers/RaceViewController.java +++ b/src/main/java/seng302/controllers/RaceViewController.java @@ -1,6 +1,6 @@ package seng302.controllers; -import javafx.animation.Animation; +import java.io.IOException; import javafx.animation.KeyFrame; import javafx.animation.Timeline; import javafx.beans.value.ChangeListener; @@ -12,7 +12,6 @@ import javafx.scene.control.Button; import javafx.scene.control.CheckBox; import javafx.scene.control.Slider; import javafx.scene.layout.AnchorPane; -import javafx.scene.layout.Pane; import javafx.scene.layout.VBox; import javafx.scene.paint.Color; import javafx.scene.paint.Paint; @@ -25,16 +24,16 @@ import seng302.controllers.annotations.Annotation; import seng302.controllers.annotations.ImportantAnnotationController; import seng302.controllers.annotations.ImportantAnnotationDelegate; import seng302.controllers.annotations.ImportantAnnotationsState; -import seng302.models.*; -import seng302.models.parsers.StreamParser; - -import java.io.IOException; -import java.util.*; +import seng302.models.BoatGroup; +import seng302.models.RaceObject; +import seng302.models.Yacht; +import seng302.models.stream.StreamParser; /** * Created by ptg19 on 29/03/17. */ -public class RaceViewController extends Thread implements ImportantAnnotationDelegate{ +public class RaceViewController extends Thread implements ImportantAnnotationDelegate { + @FXML private VBox positionVbox; @FXML @@ -52,12 +51,8 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel @FXML private CanvasController includedCanvasController; - private ArrayList startingBoats = new ArrayList<>(); private boolean displayFps; private Timeline timerTimeline; - private Map timelineInfos = new HashMap<>(); - private ArrayList boatOrder = new ArrayList<>(); - private Race race; private Stage stage; private ImportantAnnotationsState importantAnnotations; @@ -65,24 +60,12 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel // Load a default important annotation state importantAnnotations = new ImportantAnnotationsState(); - RaceController raceController = new RaceController(); - raceController.initializeRace(); - race = raceController.getRace(); - - for (Yacht boat : race.getBoats()) { - startingBoats.add(boat); - } - includedCanvasController.setup(this); includedCanvasController.initializeCanvas(); initializeTimer(); initializeSettings(); initialiseWindDirection(); initialisePositionVBox(); - //set wind direction!!!!!!! can't find another place to put my code --haoming -// double windDirection = new ConfigParser("/config/config.xml").getWindDirection(); -// windDirectionText.setText(String.format("%.1f°", windDirection)); -// windArrowText.setRotate(windDirection); includedCanvasController.timer.start(); selectAnnotationBtn.setOnAction(event -> { @@ -92,11 +75,12 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel /** * The important annotations have been changed, update this view + * * @param importantAnnotationsState The current state of the selected annotations */ - public void importantAnnotationsChanged(ImportantAnnotationsState importantAnnotationsState){ + public void importantAnnotationsChanged(ImportantAnnotationsState importantAnnotationsState) { this.importantAnnotations = importantAnnotationsState; - setAnnotations((int)annotationSlider.getValue()); // Refresh the displayed annotations + setAnnotations((int) annotationSlider.getValue()); // Refresh the displayed annotations } /** @@ -108,11 +92,13 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel Stage stage = new Stage(); // Set controller - ImportantAnnotationController controller = new ImportantAnnotationController(this, stage); + ImportantAnnotationController controller = new ImportantAnnotationController(this, + stage); fxmlLoader.setController(controller); // Load FXML and set CSS - fxmlLoader.setLocation(getClass().getResource("/views/importantAnnotationSelectView.fxml")); + fxmlLoader + .setLocation(getClass().getResource("/views/importantAnnotationSelectView.fxml")); Scene scene = new Scene(fxmlLoader.load(), 469, 248); scene.getStylesheets().add(getClass().getResource("/css/master.css").toString()); stage.initStyle(StageStyle.UNDECORATED); @@ -132,7 +118,8 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel toggleFps.selectedProperty().addListener(new ChangeListener() { @Override - public void changed(ObservableValue observable, Boolean oldValue, Boolean newValue) { + public void changed(ObservableValue observable, Boolean oldValue, + Boolean newValue) { displayFps = !displayFps; } }); @@ -141,10 +128,18 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel annotationSlider.setLabelFormatter(new StringConverter() { @Override public String toString(Double n) { - if (n == 0) return "None"; - if (n == 1) return "Low"; - if (n == 2) return "Important"; - if (n == 3) return "All"; + if (n == 0) { + return "None"; + } + if (n == 1) { + return "Low"; + } + if (n == 2) { + return "Important"; + } + if (n == 3) { + return "All"; + } return "All"; } @@ -168,25 +163,25 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel }); annotationSlider.valueProperty().addListener((obs, oldval, newVal) -> - setAnnotations((int)annotationSlider.getValue())); + setAnnotations((int) annotationSlider.getValue())); annotationSlider.setValue(3); } - private void initializeTimer(){ + private void initializeTimer() { timerTimeline = new Timeline(); timerTimeline.setCycleCount(Timeline.INDEFINITE); // Run timer update every second timerTimeline.getKeyFrames().add( - new KeyFrame(Duration.seconds(1), - event -> { - if (StreamParser.isRaceFinished()) { - timerLabel.setFill(Color.RED); - timerLabel.setText("Race Finished!"); - } else { - timerLabel.setText(currentTimer()); - } - }) + new KeyFrame(Duration.seconds(1), + event -> { + if (StreamParser.isRaceFinished()) { + timerLabel.setFill(Color.RED); + timerLabel.setText("Race Finished!"); + } else { + timerLabel.setText(currentTimer()); + } + }) ); // Start the timer @@ -197,11 +192,12 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel Timeline windDirTimeline = new Timeline(); windDirTimeline.setCycleCount(Timeline.INDEFINITE); windDirTimeline.getKeyFrames().add( - new KeyFrame(Duration.seconds(1), - event -> { - windDirectionText.setText(String.format("%.1f°", StreamParser.getWindDirection())); - windArrowText.setRotate(StreamParser.getWindDirection()); - }) + new KeyFrame(Duration.seconds(1), + event -> { + windDirectionText + .setText(String.format("%.1f°", StreamParser.getWindDirection())); + windArrowText.setRotate(StreamParser.getWindDirection()); + }) ); windDirTimeline.playFromStart(); } @@ -211,137 +207,12 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel Timeline posVBoxTimeline = new Timeline(); posVBoxTimeline.setCycleCount(Timeline.INDEFINITE); posVBoxTimeline.getKeyFrames().add( - new KeyFrame(Duration.seconds(1), - event -> { - showOrder(); - }) + new KeyFrame(Duration.seconds(1), + event -> { + showOrder(); + }) ); posVBoxTimeline.playFromStart(); - - } - - /** - * Generates time line for each boat, and stores time time into timelineInfos hash map - */ - private void initializeTimelines() { - HashMap boat_events = race.getEvents(); - for (Yacht boat : boat_events.keySet()) { - startingBoats.add(boat); -// // x, y are the real time coordinates -// DoubleProperty x = new SimpleDoubleProperty(); -// DoubleProperty y = new SimpleDoubleProperty(); -// -// List keyFrames = new ArrayList<>(); -// List events = boat_events.get(boat); -// -// // iterates all events and convert each event to keyFrame, then add them into a list -// for (Event event : events) { -// if (event.getIsFinishingEvent()) { -// keyFrames.add( -// new KeyFrame(Duration.seconds(event.getTime()), -// onFinished -> {race.setBoatFinished(boat); handleEvent(event);}, -// new KeyValue(x, event.getThisMark().getLatitude()), -// new KeyValue(y, event.getThisMark().getLongitude()) -// ) -// ); -// } else { -// keyFrames.add( -// new KeyFrame(Duration.seconds(event.getTime()), -// onFinished ->{ -// handleEvent(event); -// boat.setHeading(event.getBoatHeading()); -// }, -// new KeyValue(x, event.getThisMark().getLatitude()), -// new KeyValue(y, event.getThisMark().getLongitude()) -// ) -// ); -// } -// } -// timelineInfos.put(boat, new TimelineInfo(new Timeline(keyFrames.toArray(new KeyFrame[keyFrames.size()])), x, y)); - } - setRaceDuration(); - } - - private void setRaceDuration(){ - Double maxDuration = 0.0; - Timeline maxTimeline = null; - - for (TimelineInfo timelineInfo : timelineInfos.values()) { - - Timeline timeline = timelineInfo.getTimeline(); - if (timeline.getTotalDuration().toMillis() >= maxDuration) { - maxDuration = timeline.getTotalDuration().toMillis(); - maxTimeline = timeline; - } - - // Timelines are paused by default - timeline.play(); - timeline.pause(); - } - - maxTimeline.setOnFinished(event -> { - race.setRaceFinished(); - loadRaceResultView(); - }); - } - - /** - * Play each boats timerTimeline - */ - public void playTimelines(){ - for (TimelineInfo timelineInfo : timelineInfos.values()){ - Timeline timeline = timelineInfo.getTimeline(); - - if (timeline.getStatus() == Animation.Status.PAUSED){ - timeline.play(); - } - } - } - - /** - * Pause each boats timerTimeline - */ - public void pauseTimelines(){ - for (TimelineInfo timelineInfo : timelineInfos.values()){ - Timeline timeline = timelineInfo.getTimeline(); - - if (timeline.getStatus() == Animation.Status.RUNNING){ - timeline.pause(); - } - } - } - - /** - * Display the list of boats in the order they finished the race - */ - private void loadRaceResultView() { - FXMLLoader loader = new FXMLLoader(getClass().getResource("/views/FinishView.fxml")); - loader.setController(new RaceResultController(race)); - - try { - contentAnchorPane.getChildren().removeAll(); - contentAnchorPane.getChildren().clear(); - contentAnchorPane.getChildren().addAll((Pane) loader.load()); - - } catch (javafx.fxml.LoadException e) { - System.err.println(e.getCause()); - } catch (IOException e) { - System.err.println(e); - } - } - - public void handleEvent(Event event) { - Yacht boat = event.getBoat(); - boatOrder.remove(boat); - boat.setMarkLastPast(event.getMarkPosInRace()); - boatOrder.add(boat); - boatOrder.sort(new Comparator() { - @Override - public int compare(Yacht b1, Yacht b2) { - return b2.getMarkLastPast() - b1.getMarkLastPast(); - } - }); - showOrder(); } private void showOrder() { @@ -349,20 +220,16 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel positionVbox.getChildren().removeAll(); positionVbox.getStylesheets().add(getClass().getResource("/css/master.css").toString()); -// for (Boat boat : boatOrder) { -// positionVbox.getChildren().add(new Text(boat.getShortName() + " " + boat.getSpeedInKnots() + " Knots")); -// } - for (Yacht boat : StreamParser.getBoatsPos().values()) { if (boat.getBoatStatus() == 3) { // 3 is finish status Text textToAdd = new Text(boat.getPosition() + ". " + - boat.getShortName() + " (Finished)"); + boat.getShortName() + " (Finished)"); textToAdd.setFill(Paint.valueOf("#d3d3d3")); positionVbox.getChildren().add(textToAdd); } else { Text textToAdd = new Text(boat.getPosition() + ". " + - boat.getShortName() + " "); + boat.getShortName() + " "); textToAdd.setFill(Paint.valueOf("#d3d3d3")); textToAdd.setStyle(""); positionVbox.getChildren().add(textToAdd); @@ -404,118 +271,83 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel return timerString; } - public void stopTimer() { - timerTimeline.stop(); - } - public void startTimer() { - timerTimeline.play(); - } - public boolean isDisplayFps() { return displayFps; } - public Race getRace() { - return race; - } - - public Map getTimelineInfos() { - return timelineInfos; - } - - public ArrayList getStartingBoats(){ - return startingBoats; - } - /** * Display the important annotations for a specific BoatGroup + * * @param bg The boat group to set the annotations for */ - private void setBoatGroupImportantAnnotations(BoatGroup bg){ - if (importantAnnotations.getAnnotationState(Annotation.NAME)){ + private void setBoatGroupImportantAnnotations(BoatGroup bg) { + if (importantAnnotations.getAnnotationState(Annotation.NAME)) { bg.setTeamNameObjectVisible(true); - } - else{ + } else { bg.setTeamNameObjectVisible(false); } - if (importantAnnotations.getAnnotationState(Annotation.SPEED)){ + if (importantAnnotations.getAnnotationState(Annotation.SPEED)) { bg.setVelocityObjectVisible(true); - } - else{ + } else { bg.setVelocityObjectVisible(false); } - if (importantAnnotations.getAnnotationState(Annotation.TRACK)){ + if (importantAnnotations.getAnnotationState(Annotation.TRACK)) { bg.setLineGroupVisible(true); - } - else{ + } else { bg.setLineGroupVisible(false); } - if (importantAnnotations.getAnnotationState(Annotation.WAKE)){ + if (importantAnnotations.getAnnotationState(Annotation.WAKE)) { bg.setWakeVisible(true); - } - else{ + } else { bg.setWakeVisible(false); } } private void setAnnotations(Integer annotationLevel) { switch (annotationLevel) { - // No Annotations case 0: - for (RaceObject ro : includedCanvasController.getRaceObjects()) { - if(ro instanceof BoatGroup) { - BoatGroup bg = (BoatGroup) ro; - bg.setTeamNameObjectVisible(false); - bg.setVelocityObjectVisible(false); - bg.setLineGroupVisible(false); - bg.setWakeVisible(false); - } + for (BoatGroup bg : includedCanvasController.getBoatGroups()) { + bg.setTeamNameObjectVisible(false); + bg.setVelocityObjectVisible(false); + bg.setLineGroupVisible(false); + bg.setWakeVisible(false); } break; - // Low Annotations case 1: - for (RaceObject ro : includedCanvasController.getRaceObjects()) { - if(ro instanceof BoatGroup) { - BoatGroup bg = (BoatGroup) ro; - bg.setTeamNameObjectVisible(true); - bg.setVelocityObjectVisible(false); - bg.setLineGroupVisible(false); - bg.setWakeVisible(false); - } + for (BoatGroup bg : includedCanvasController.getBoatGroups()) { + bg.setTeamNameObjectVisible(true); + bg.setVelocityObjectVisible(false); + bg.setLineGroupVisible(false); + bg.setWakeVisible(false); } break; - // Important Annotations case 2: - for (RaceObject ro : includedCanvasController.getRaceObjects()) { - if(ro instanceof BoatGroup) { - BoatGroup bg = (BoatGroup) ro; - setBoatGroupImportantAnnotations(bg); - } + for (BoatGroup bg : includedCanvasController.getBoatGroups()) { + bg.setTeamNameObjectVisible(true); + bg.setVelocityObjectVisible(false); + bg.setLineGroupVisible(true); + bg.setWakeVisible(false); } break; - // All Annotations case 3: - for (RaceObject ro : includedCanvasController.getRaceObjects()) { - if(ro instanceof BoatGroup) { - BoatGroup bg = (BoatGroup) ro; - bg.setTeamNameObjectVisible(true); - bg.setVelocityObjectVisible(true); - bg.setLineGroupVisible(true); - bg.setWakeVisible(true); - } + for (BoatGroup bg : includedCanvasController.getBoatGroups()) { + bg.setTeamNameObjectVisible(true); + bg.setVelocityObjectVisible(true); + bg.setLineGroupVisible(true); + bg.setWakeVisible(true); } break; } } - void setStage (Stage stage) { + void setStage(Stage stage) { this.stage = stage; } - Stage getStage () { + Stage getStage() { return stage; } } \ No newline at end of file diff --git a/src/main/java/seng302/models/BoatGroup.java b/src/main/java/seng302/models/BoatGroup.java index 327ae1ba..ed594276 100644 --- a/src/main/java/seng302/models/BoatGroup.java +++ b/src/main/java/seng302/models/BoatGroup.java @@ -19,7 +19,7 @@ import java.util.List; * UpdatePosition is called unless the window is minimized in which case it attempts to store animations and apply them * when the window is maximised. */ -public class BoatGroup extends RaceObject{ +public class BoatGroup extends Group{ //Constants for drawing private static final double TEAMNAME_X_OFFSET = 10d; @@ -30,8 +30,15 @@ public class BoatGroup extends RaceObject{ private static final double BOAT_WIDTH = 10d; //Variables for boat logic. private Point2D lastPoint; - private int wakeGenerationDelay = 10; - private double distanceTravelled; + double oldTime; + double newTime; + double lastYValue = 0; + double lastXValue = 0; + private double dx; + private double dy; + private double pixelVelocityX; + private double pixelVelocityY; + private static final int expectedUpdateInterval = 200; //Graphical objects private Yacht boat; private Group lineGroup = new Group(); @@ -39,14 +46,6 @@ public class BoatGroup extends RaceObject{ private Text teamNameObject; private Text velocityObject; private Wake wake; - //Handles boat moving when connecting to a stream - private boolean setToInitialLocation = false; - private boolean destinationSet; - //Variables for handling minimization - private Stage stage; - private boolean isMaximized= true; - private List lineStorage = new ArrayList<>(); - private int setCallCount = 5; /** * Creates a BoatGroup with the default triangular boat polygon. @@ -91,7 +90,6 @@ public class BoatGroup extends RaceObject{ velocityObject.setX(VELOCITY_X_OFFSET); velocityObject.setY(VELOCITY_Y_OFFSET); velocityObject.relocate(velocityObject.getX(), velocityObject.getY()); - destinationSet = false; wake = new Wake(0, -BOAT_HEIGHT); super.getChildren().addAll(teamNameObject, velocityObject, boatPoly); @@ -103,9 +101,9 @@ public class BoatGroup extends RaceObject{ */ private void initChildren (Color color) { initChildren(color, - -BOAT_WIDTH / 2, BOAT_HEIGHT / 2, - 0.0, -BOAT_HEIGHT / 2, - BOAT_WIDTH / 2, BOAT_HEIGHT / 2); + -BOAT_WIDTH / 2, BOAT_HEIGHT / 2, + 0.0, -BOAT_HEIGHT / 2, + BOAT_WIDTH / 2, BOAT_HEIGHT / 2); } /** @@ -113,7 +111,7 @@ public class BoatGroup extends RaceObject{ * @param dx The amount to move the X coordinate by * @param dy The amount to move the Y coordinate by */ - public void moveGroupBy(double dx, double dy, double rotation) { + public void moveGroupBy(double dx, double dy) { boatPoly.setLayoutX(boatPoly.getLayoutX() + dx); boatPoly.setLayoutY(boatPoly.getLayoutY() + dy); teamNameObject.setLayoutX(teamNameObject.getLayoutX() + dx); @@ -122,19 +120,16 @@ public class BoatGroup extends RaceObject{ velocityObject.setLayoutY(velocityObject.getLayoutY() + dy); wake.setLayoutX(wake.getLayoutX() + dx); wake.setLayoutY(wake.getLayoutY() + dy); - currentRotation = rotation + currentRotation; - boatPoly.getTransforms().setAll(new Rotate(rotation)); } + /** * Moves the boat and its children annotations to coordinates specified * @param x The X coordinate to move the boat to * @param y The Y coordinate to move the boat to - * @param rotation The heading in degrees from north the boat should rotate to. */ public void moveTo (double x, double y, double rotation) { - currentRotation = rotation; - boatPoly.getTransforms().setAll(new Rotate(rotation)); + rotateTo(rotation); boatPoly.setLayoutX(x); boatPoly.setLayoutY(y); teamNameObject.setLayoutX(x); @@ -143,42 +138,14 @@ public class BoatGroup extends RaceObject{ velocityObject.setLayoutY(y); wake.setLayoutX(x); wake.setLayoutY(y); - wake.rotate(currentRotation); } - /** - * Updates the position of all graphics in the BoatGroup based off of the given time interval. - * @param timeInterval The interval, in milliseconds, the boat should update it's position based on. - */ - public void updatePosition (long timeInterval) { - //Calculate the movement of the boat. - if (isMaximized) { - double dx = pixelVelocityX * timeInterval; - double dy = pixelVelocityY * timeInterval; - double rotation = rotationalVelocity * timeInterval; - distanceTravelled += Math.abs(dx) + Math.abs(dy); - moveGroupBy(dx, dy, rotation); + public void rotateTo (double rotation) { + boatPoly.getTransforms().setAll(new Rotate(rotation)); + } - //Draw a new section of the trail every 20 pixels of movement. - if (distanceTravelled > 20) { - distanceTravelled = 0; - if (lastPoint != null) { - Line l = new Line( - lastPoint.getX(), - lastPoint.getY(), - boatPoly.getLayoutX(), - boatPoly.getLayoutY() - ); - l.getStrokeDashArray().setAll(3d, 7d); - l.setStroke(boatPoly.getFill()); - lineGroup.getChildren().add(l); - } - if (destinationSet) { //Only begin drawing after the first destination is set - lastPoint = new Point2D(boatPoly.getLayoutX(), boatPoly.getLayoutY()); - } - } - wake.updatePosition(timeInterval); - } + public void updatePosition () { + moveGroupBy(dx, dy); } /** @@ -188,59 +155,26 @@ public class BoatGroup extends RaceObject{ * @param rotation Rotation to move graphics to. * @param raceIds RaceID of the object to move. */ - public void setDestination (double newXValue, double newYValue, double rotation, double groundSpeed, int... raceIds) { - if (hasRaceId(raceIds)) { - if (setToInitialLocation) { - destinationSet = true; - boat.setVelocity(groundSpeed); - if (currentRotation < 0) - currentRotation = 360 - currentRotation; - double dx = newXValue - boatPoly.getLayoutX(); - double dy = newYValue - boatPoly.getLayoutY(); + public void setDestination (double newXValue, double newYValue, double rotation, double groundSpeed, long raceIds) { + System.currentTimeMillis(); + moveTo(lastXValue, lastYValue, rotation); - pixelVelocityX = dx / expectedUpdateInterval; - pixelVelocityY = dy / expectedUpdateInterval; - rotationalGoal = rotation; - calculateRotationalVelocity(); + dx = (newXValue - lastXValue)/12; + dy = (newYValue - lastYValue)/12; - if (wakeGenerationDelay > 0) { - wake.rotate(rotationalGoal); - rotationalVelocity = 0; - wakeGenerationDelay--; - } else { - wake.setRotationalVelocity(rotationalVelocity, rotationalGoal, boat.getVelocity()); - } - velocityObject.setText(String.format("%.2f m/s", boat.getVelocity())); - } else { - setToInitialLocation = true; - rotationalGoal = rotation; - moveTo(newXValue, newYValue, rotation); - } - } - //If minimized generate lines every 5 calls to set destination. - if (!isMaximized) { - setToInitialLocation = false; - wakeGenerationDelay = 2; - if(setCallCount-- == 0) { - setCallCount = 5; - if (lastPoint != null) { - Line l = new Line( - lastPoint.getX(), - lastPoint.getY(), - newXValue, - newYValue - ); - l.getStrokeDashArray().setAll(3d, 7d); - l.setStroke(boatPoly.getFill()); - lineStorage.add(l); - } - if (destinationSet) { //Only begin drawing after the first destination is set - lastPoint = new Point2D(newXValue, newYValue); - } - } - } + lastXValue = newXValue; + lastYValue = newYValue; + + boat.setVelocity(groundSpeed); + velocityObject.setText(String.format("%.2f m/s", boat.getVelocity())); } + + + + + + public void setTeamNameObjectVisible(Boolean visible) { teamNameObject.setVisible(visible); } @@ -261,27 +195,27 @@ public class BoatGroup extends RaceObject{ return boat; } - /** - * Returns true if this BoatGroup contains at least one of the given IDs. - * - * @param raceIds The ID's to check the BoatGroup for. - * @return True if the BoatGroup contains at east one of the given IDs, false otherwise. - */ - public boolean hasRaceId (int... raceIds) { - for (int id : raceIds) { - if (id == boat.getSourceID()) - return true; - } - return false; - } +// /** +// * Returns true if this BoatGroup contains at least one of the given IDs. +// * +// * @param raceIds The ID's to check the BoatGroup for. +// * @return True if the BoatGroup contains at east one of the given IDs, false otherwise. +// */ +// public boolean hasRaceId (long... raceIds) { +// for (long id : raceIds) { +// if (id == boat.getSourceID()) +// return true; +// } +// return false; +// } /** * Returns all raceIds associated with this group. For BoatGroups the ID's are for the boat. * * @return An array containing all ID's associated with this RaceObject. */ - public int[] getRaceIds () { - return new int[] {boat.getSourceID()}; + public long getRaceId() { + return boat.getSourceID(); } /** @@ -296,25 +230,4 @@ public class BoatGroup extends RaceObject{ group.getChildren().addAll(wake, lineGroup); return group; } - - /** - * Use this function to let the BoatGroup know about the stage it is in. If it knows about it's stage then it will - * listen to the iconified property of that stage and change it's behaviour upon minimization. Without setting the - * Stage there is guarantee that the BoatGroup will draw properly when the stage is minimized. - * - * @param stage The stage that the BoatGroup is added to. - */ - public void setStage (Stage stage) { - /* TODO: 4/05/17 cir27 - Find a way to get the stage to this point. Need to pass it through multiple controllers. - App.start() -> Controller.setContentPane -> RaceViewController -> CanvasController - */ - this.stage = stage; - this.stage.iconifiedProperty().addListener(e -> { - isMaximized = !stage.isIconified(); - if (!lineStorage.isEmpty()) { - lineGroup.getChildren().addAll(lineStorage); - lineStorage.clear(); - } - }); - } -} +} \ No newline at end of file diff --git a/src/main/java/seng302/models/mark/MarkGroup.java b/src/main/java/seng302/models/mark/MarkGroup.java index a4b134ad..0e886abc 100644 --- a/src/main/java/seng302/models/mark/MarkGroup.java +++ b/src/main/java/seng302/models/mark/MarkGroup.java @@ -1,12 +1,11 @@ package seng302.models.mark; import javafx.geometry.Point2D; -import javafx.scene.Node; +import javafx.scene.Group; import javafx.scene.paint.Color; import javafx.scene.shape.Circle; import javafx.scene.shape.Line; import javafx.scene.transform.Rotate; -import seng302.models.RaceObject; import java.util.ArrayList; import java.util.List; @@ -14,7 +13,7 @@ import java.util.List; /** * Created by CJIRWIN on 26/04/2017. */ -public class MarkGroup extends RaceObject { +public class MarkGroup extends Group { private static int MARK_RADIUS = 5; private static int LINE_THICKNESS = 2; @@ -23,14 +22,8 @@ public class MarkGroup extends RaceObject { private List marks = new ArrayList<>(); private Mark mainMark; - private double[] nodePixelVelocitiesX; - private double[] nodePixelVelocitiesY; - private Point2D[] nodeDestinations; public MarkGroup (Mark mark, Point2D... points) { - nodePixelVelocitiesX = new double[points.length]; - nodePixelVelocitiesY = new double[points.length]; - nodeDestinations = new Point2D[points.length]; marks.add(mark); mainMark = mark; Color color = Color.BLACK; @@ -42,45 +35,33 @@ public class MarkGroup extends RaceObject { Circle markCircle; if (mark.getMarkType() == MarkType.SINGLE_MARK) { markCircle = new Circle( - points[0].getX(), - points[0].getY(), - MARK_RADIUS, - color + points[0].getX(), + points[0].getY(), + MARK_RADIUS, + color ); - nodeDestinations = new Point2D[]{ - new Point2D(markCircle.getCenterX(), markCircle.getCenterY() - ) - }; super.getChildren().add(markCircle); } else { -// marks.add(((GateMark) mark).getSingleMark1()); -// marks.add(((GateMark) mark).getSingleMark2()); - nodePixelVelocitiesX = new double[]{0d,0d}; - nodePixelVelocitiesY = new double[]{0d,0d}; - nodeDestinations = new Point2D[2]; - markCircle = new Circle( - points[0].getX(), - points[0].getY(), - MARK_RADIUS, - color + points[0].getX(), + points[0].getY(), + MARK_RADIUS, + color ); - nodeDestinations[0] = new Point2D(markCircle.getCenterX(), markCircle.getCenterY()); super.getChildren().add(markCircle); markCircle = new Circle( - points[1].getX(), - points[1].getY(), - MARK_RADIUS, - color + points[1].getX(), + points[1].getY(), + MARK_RADIUS, + color ); - nodeDestinations[1] = new Point2D(markCircle.getCenterX(), markCircle.getCenterY()); super.getChildren().add(markCircle); Line line = new Line( - points[0].getX(), - points[0].getY(), - points[1].getX(), - points[1].getY() + points[0].getX(), + points[0].getY(), + points[1].getX(), + points[1].getY() ); line.setStrokeWidth(LINE_THICKNESS); line.setStroke(color); @@ -91,132 +72,38 @@ public class MarkGroup extends RaceObject { } } - public void setDestination (double x, double y, double rotation, double groundSpeed, int... raceIds) { - for (int i = 0; i < marks.size(); i++) - for (int id : raceIds) - if (id == marks.get(i).getId()) - setDestinationChild(x, y, 0, Math.max(0, i-1)); - this.rotationalGoal = rotation; - calculateRotationalVelocity(); - } - - - private void setDestinationChild (double x, double y, double speed, int childIndex) { - //double relativeX = x - super.getLayoutX(); - //double relativeY = y - super.getLayoutY(); - Circle markCircle = (Circle) super.getChildren().get(childIndex); - this.nodeDestinations[childIndex] = new Point2D(x, y); - //if (Math.abs(relativeX - markCircle.getCenterX()) > 30 && Math.abs(relativeY - markCircle.getCenterY()) > 30) { - this.nodePixelVelocitiesX[childIndex] = (x - markCircle.getCenterX()) / expectedUpdateInterval; - this.nodePixelVelocitiesY[childIndex] = (y - markCircle.getCenterY()) / expectedUpdateInterval; - //} - } - - public void rotateTo (double rotation) { - if (mainMark.getMarkType() != MarkType.SINGLE_MARK) { - Line line = (Line) super.getChildren().get(2); - double xCenter = Math.abs(line.getEndX() - line.getStartX()); - double yCenter = Math.abs(line.getEndY() - line.getStartY()); - super.getTransforms().setAll(new Rotate(rotation, xCenter, yCenter)); - } - } - - public void updatePosition (long timeInterval) { - Circle markCircle = (Circle) super.getChildren().get(0); - - if (nodePixelVelocitiesX[0] > 0 && markCircle.getCenterX() > nodeDestinations[0].getX() || - nodePixelVelocitiesX[0] < 0 && markCircle.getCenterX() < nodeDestinations[0].getY()) - nodePixelVelocitiesX[0] = 0; - else if (nodePixelVelocitiesX[0] != 0) - markCircle.setCenterX(markCircle.getCenterX() + nodePixelVelocitiesX[0] * timeInterval); - - if (nodePixelVelocitiesY[0] > 0 && markCircle.getCenterY() > nodeDestinations[0].getY() || - nodePixelVelocitiesY[0] < 0 && markCircle.getCenterY() < nodeDestinations[0].getY()) - nodePixelVelocitiesY[0] = 0; - else if (nodePixelVelocitiesY[0] != 0) - markCircle.setCenterY(markCircle.getCenterY() + nodePixelVelocitiesY[0] * timeInterval); - - if (mainMark.getMarkType() != MarkType.SINGLE_MARK) { - - Line line = (Line) super.getChildren().get(2); - line.setStartX(markCircle.getCenterX()); - line.setStartY(markCircle.getCenterY()); - - markCircle = (Circle) super.getChildren().get(1); - - if (nodePixelVelocitiesX[1] > 0 && markCircle.getCenterX() >= nodeDestinations[1].getX() || - nodePixelVelocitiesX[1] < 0 && markCircle.getCenterX() <= nodeDestinations[1].getX()) - nodePixelVelocitiesX[1] = 0; - else if (nodePixelVelocitiesX[1] != 0) - markCircle.setCenterX(markCircle.getCenterX() + nodePixelVelocitiesX[1] * timeInterval); - - if (nodePixelVelocitiesY[1] > 0 && markCircle.getCenterY() > nodeDestinations[1].getY() || - nodePixelVelocitiesY[1] < 0 && markCircle.getCenterY() < nodeDestinations[1].getY()) - nodePixelVelocitiesY[1] = 0; - else if (nodePixelVelocitiesY[1] != 0) - markCircle.setCenterY(markCircle.getCenterY() + nodePixelVelocitiesY[1] * timeInterval); - line.setEndX(markCircle.getCenterX()); - line.setEndY(markCircle.getCenterY()); - } - } - - public void moveGroupBy (double x, double y, double rotation) { - if (mainMark.getMarkType() != MarkType.SINGLE_MARK) { - Line line = (Line) super.getChildren().get(2); - for (int childIndex = 0; childIndex < 2; childIndex++){ - Circle mark = (Circle) super.getChildren().get(childIndex); - mark.setCenterY(mark.getCenterY() + y); - mark.setCenterX(mark.getCenterX() + x); - } - line.setStartX(line.getStartX() + x); - line.setStartY(line.getStartY() + y); - line.setEndX(line.getEndX() + x); - line.setEndY(line.getEndY() + y); - } else { - Circle mark = (Circle) super.getChildren().get(0); - mark.setCenterY(mark.getCenterY() + y); - mark.setCenterX(mark.getCenterX() + x); - } - rotateTo(currentRotation + rotation); - } - - public void moveTo (double x, double y, double rotation) { - moveTo(x, y); - rotateTo(rotation); - } - - public void moveTo (double x, double y) { - Circle markCircle = (Circle) super.getChildren().get(0); - markCircle.setCenterX(x); - markCircle.setCenterY(y); - if (mainMark.getMarkType() != MarkType.SINGLE_MARK) { - markCircle = (Circle) super.getChildren().get(1); + public void moveMarkTo (double x, double y, int raceId) + { + if (mainMark.getMarkType() == MarkType.SINGLE_MARK) { + Circle markCircle = (Circle) super.getChildren().get(0); markCircle.setCenterX(x); markCircle.setCenterY(y); - Line line = (Line) super.getChildren().get(2); - line.setStartX(x); - line.setStartY(y); - line.setEndX(x); - line.setEndY(y); + } else { + Circle markCircle1 = (Circle) super.getChildren().get(0); + Circle markCircle2 = (Circle) super.getChildren().get(1); + Line connectingLine = (Line) super.getChildren().get(2); + if (marks.get(1).getId() == raceId) { + markCircle1.setCenterX(x); + markCircle1.setCenterY(y); + connectingLine.setStartX(markCircle1.getCenterX()); + connectingLine.setStartY(markCircle1.getCenterY()); + } else if (marks.get(2).getId() == raceId) { + markCircle2.setCenterX(x); + markCircle2.setCenterY(y); + connectingLine.setEndX(markCircle2.getCenterX()); + connectingLine.setEndY(markCircle2.getCenterY()); + } } } public boolean hasRaceId (int... raceIds) { for (int id : raceIds) for (Mark mark : marks) - if (id == mark.getId()) - return true; + if (id == mark.getId()) + return true; return false; } - public static int getMarkRadius() { - return MARK_RADIUS; - } - - public static void setMarkRadius(int markRadius) { - MARK_RADIUS = markRadius; - } - public int[] getRaceIds () { int[] idArray = new int[marks.size()]; int i = 0; @@ -224,4 +111,4 @@ public class MarkGroup extends RaceObject { idArray[i++] = mark.getId(); return idArray; } -} +} \ No newline at end of file diff --git a/src/main/java/seng302/models/stream/StreamParser.java b/src/main/java/seng302/models/stream/StreamParser.java index e703941d..51769a1d 100644 --- a/src/main/java/seng302/models/stream/StreamParser.java +++ b/src/main/java/seng302/models/stream/StreamParser.java @@ -205,7 +205,6 @@ public class StreamParser extends Thread{ raceFinished = false; System.out.println("[CLIENT] Race has started"); } - //System.out.println("Time since start: " + -1 * timeTillStart + " Seconds"); timeSinceStart = timeTillStart; } long windDir = bytesToLong(Arrays.copyOfRange(payload,18,20)); @@ -214,11 +213,10 @@ public class StreamParser extends Thread{ long windSpeed = bytesToLong(Arrays.copyOfRange(payload,20,22)); int noBoats = payload[22]; int raceType = payload[23]; -// ArrayList boatStatuses = new ArrayList<>(); boatsPos = new TreeMap<>(); for (int i = 0; i < noBoats; i++){ - Long boatStatusSourceID = bytesToLong(Arrays.copyOfRange(payload,24 + (i * 20),28+ (i * 20))); - Yacht boat = boats.get((int)(long) boatStatusSourceID); + long boatStatusSourceID = bytesToLong(Arrays.copyOfRange(payload,24 + (i * 20),28+ (i * 20))); + Yacht boat = boats.get((int) boatStatusSourceID); boat.setBoatStatus((int)payload[28 + (i * 20)]); boat.setLegNumber((int)payload[29 + (i * 20)]); boat.setPenaltiesAwarded((int)payload[29 + (i * 20)]); @@ -281,7 +279,6 @@ public class StreamParser extends Thread{ int messageType = payload[9]; long messagelength = bytesToLong(Arrays.copyOfRange(payload,12,14)); String xmlMessage = new String((Arrays.copyOfRange(payload,14,(int) (14 + messagelength)))).trim(); - //System.out.println("xmlMessage2 = " + xmlMessage); //Create XML document Object DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); @@ -344,7 +341,6 @@ public class StreamParser extends Thread{ long subjectId = bytesToLong(Arrays.copyOfRange(payload,9,13)); long incidentId = bytesToLong(Arrays.copyOfRange(payload,13,17)); int eventId = payload[17]; -// System.out.println("eventId = " + eventId); } /** @@ -382,19 +378,18 @@ public class StreamParser extends Thread{ double groundSpeed = bytesToLong(Arrays.copyOfRange(payload,38,40))/1000.0; //type 1 is a racing yacht and type 3 is a mark, needed for updating positions of the mark and boat - if (deviceType == 1 || deviceType == 3){ + if (deviceType == 1){ BoatPositionPacket boatPacket = new BoatPositionPacket(boatId, timeValid, lat, lon, heading, groundSpeed); //add a new priority que to the boatPositions HashMap if (!boatPositions.containsKey(boatId)){ - boatPositions.put(boatId, new PriorityBlockingQueue(256, new Comparator() { + boatPositions.put(boatId, new PriorityBlockingQueue<>(256, new Comparator() { @Override public int compare(BoatPositionPacket p1, BoatPositionPacket p2) { return (int) (p1.getTimeValid() - p2.getTimeValid()); } })); } - //Adding the boatPacket to the priority que boatPositions.get(boatId).put(boatPacket); } } diff --git a/src/test/java/seng302/models/stream/StreamReceiverTest.java b/src/test/java/seng302/models/stream/StreamReceiverTest.java index d713efda..4d0bea44 100644 --- a/src/test/java/seng302/models/stream/StreamReceiverTest.java +++ b/src/test/java/seng302/models/stream/StreamReceiverTest.java @@ -2,13 +2,13 @@ package seng302.models.stream; import org.junit.Before; import org.junit.Test; -import seng302.models.parsers.packets.StreamPacket; import java.io.*; import java.lang.reflect.Method; import java.net.Socket; import java.util.Comparator; import java.util.concurrent.PriorityBlockingQueue; +import seng302.models.stream.packets.StreamPacket; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; From aaa3dc93f13ba639b044ee78723b0efa4a60b006 Mon Sep 17 00:00:00 2001 From: Peter Galloway Date: Wed, 17 May 2017 17:34:47 +1200 Subject: [PATCH 12/32] boat movement working reliably now, still need to fix one bug at initialization #story[923] --- src/main/java/seng302/App.java | 2 +- .../seng302/controllers/CanvasController.java | 65 +++++++++++-------- src/main/java/seng302/models/BoatGroup.java | 55 +++++++++++----- .../server/messages/BoatLocationMessage.java | 2 +- 4 files changed, 77 insertions(+), 47 deletions(-) diff --git a/src/main/java/seng302/App.java b/src/main/java/seng302/App.java index 92aab87a..aab0a8eb 100644 --- a/src/main/java/seng302/App.java +++ b/src/main/java/seng302/App.java @@ -62,7 +62,7 @@ public class App extends Application } //Change the StreamReceiver in this else block to change the default data source. else{ - sr = new StreamReceiver("livedata.americascup.com", 4941, "RaceStream"); + sr = new StreamReceiver("localhost", 4949, "RaceStream"); } sr.start(); diff --git a/src/main/java/seng302/controllers/CanvasController.java b/src/main/java/seng302/controllers/CanvasController.java index c1a642fc..d2e7ce02 100644 --- a/src/main/java/seng302/controllers/CanvasController.java +++ b/src/main/java/seng302/controllers/CanvasController.java @@ -51,10 +51,12 @@ public class CanvasController { private Mark maxLonPoint; private double referencePointX; private double referencePointY; + private List markGroups = new ArrayList<>(); private List boatGroups = new ArrayList<>(); //FRAME RATE + private Double frameRate = 60.0; private final long[] frameTimes = new long[30]; private int frameTimeIndex = 0; private boolean arrayFilled = false; @@ -93,7 +95,7 @@ public class CanvasController { // TODO: 1/05/17 wmu16 - Change this call to now draw the marks as from the xml - drawBoats(); + initializeBoats(); timer = new AnimationTimer() { @Override @@ -110,7 +112,7 @@ public class CanvasController { if (arrayFilled) { elapsedNanos = now - oldFrameTime ; long elapsedNanosPerFrame = elapsedNanos / frameTimes.length ; - Double frameRate = 1_000_000_000.0 / elapsedNanosPerFrame ; + frameRate = 1_000_000_000.0 / elapsedNanosPerFrame ; drawFps(frameRate.intValue()); } @@ -167,30 +169,38 @@ public class CanvasController { private void updateGroups(){ for (BoatGroup boatGroup : boatGroups) { - boatGroup.updatePosition(); // some raceObjects will have multiple ID's (for instance gate marks) //checking if the current "ID" has any updates associated with it if (StreamParser.boatPositions.containsKey(boatGroup.getRaceId())) { - moveBoatGroup(boatGroup); + if (boatGroup.isStopped()) { + updateBoatGroup(boatGroup); + } } + boatGroup.move(); } for (MarkGroup markGroup : markGroups) { for (int id : markGroup.getRaceIds()) { if (StreamParser.boatPositions.containsKey(id)) { - moveMarkGroup(id, markGroup); + UpdateMarkGroup(id, markGroup); } } } } - private void moveBoatGroup(BoatGroup boatGroup) { + private void updateBoatGroup(BoatGroup boatGroup) { PriorityBlockingQueue movementQueue = StreamParser.boatPositions.get(boatGroup.getRaceId()); - if (movementQueue.size() > 0){ + // giving the movementQueue a 5 packet buffer to account for slightly out of order packets + if (movementQueue.size() > 5){ try { BoatPositionPacket positionPacket = movementQueue.take(); Point2D p2d = findScaledXY(positionPacket.getLat(), positionPacket.getLon()); + if (boatGroup.getRaceId() == 106){ +// System.out.println("p2d.getX() = " + p2d.getX()); +// System.out.println("p2d.getY() = " + p2d.getY()); +// System.out.println("positionPacket.getTimeValid() = " + positionPacket.getTimeValid()); + } double heading = 360.0 / 0xffff * positionPacket.getHeading(); - boatGroup.setDestination(p2d.getX(), p2d.getY(), heading, positionPacket.getGroundSpeed(), boatGroup.getRaceId()); + boatGroup.setDestination(p2d.getX(), p2d.getY(), heading, positionPacket.getGroundSpeed(), positionPacket.getTimeValid(), frameRate, boatGroup.getRaceId()); } catch (InterruptedException e){ e.printStackTrace(); } @@ -198,7 +208,7 @@ public class CanvasController { } } - void moveMarkGroup (int raceId, MarkGroup markGroup) { + void UpdateMarkGroup (int raceId, MarkGroup markGroup) { PriorityBlockingQueue movementQueue = StreamParser.boatPositions.get(raceId); if (movementQueue.size() > 0){ try { @@ -211,6 +221,23 @@ public class CanvasController { } } + /** + * Draws all the boats. + */ + private void initializeBoats() { + Map boats = StreamParser.getBoats(); + Group boatAnnotations = new Group(); + + for (Yacht boat : boats.values()) { + boat.setColour(Colors.getColor()); + BoatGroup boatGroup = new BoatGroup(boat, boat.getColour()); + boatGroups.add(boatGroup); + boatAnnotations.getChildren().add(boatGroup.getLowPriorityAnnotations()); + } + group.getChildren().add(boatAnnotations); + group.getChildren().addAll(boatGroups); + } + class ResizableCanvas extends Canvas { ResizableCanvas() { @@ -236,11 +263,11 @@ public class CanvasController { public double prefWidth(double height) { return getWidth(); } - @Override public double prefHeight(double width) { return getHeight(); } + } private void drawFps(int fps){ @@ -259,23 +286,6 @@ public class CanvasController { } } - /** - * Draws all the boats. - */ - private void drawBoats() { - Map boats = StreamParser.getBoats(); - Group boatAnnotations = new Group(); - - for (Yacht boat : boats.values()) { - boat.setColour(Colors.getColor()); - BoatGroup boatGroup = new BoatGroup(boat, boat.getColour()); - boatGroups.add(boatGroup); - boatAnnotations.getChildren().add(boatGroup.getLowPriorityAnnotations()); - } - group.getChildren().add(boatAnnotations); - group.getChildren().addAll(boatGroups); - } - /** * Calculates x and y location for every marker that fits it to the canvas the race will be drawn on. */ @@ -382,6 +392,7 @@ public class CanvasController { * Give all markers in the course an x,y location relative to a given reference with a known x,y location. Distances * are scaled according to the distanceScaleFactor variable. */ + // DEPRECATED create an initialize marks method like the initialize boats method private void givePointsXY() { // List allPoints = StreamParser.getXmlObject().getRaceXML().getCompoundMarks(); // List processed = new ArrayList<>(); diff --git a/src/main/java/seng302/models/BoatGroup.java b/src/main/java/seng302/models/BoatGroup.java index ed594276..3de6d3a8 100644 --- a/src/main/java/seng302/models/BoatGroup.java +++ b/src/main/java/seng302/models/BoatGroup.java @@ -29,13 +29,16 @@ public class BoatGroup extends Group{ private static final double BOAT_HEIGHT = 15d; private static final double BOAT_WIDTH = 10d; //Variables for boat logic. + private boolean isStopped = true; + private double xIncrement; + private double yIncrement; + private long lastTimeValid = 0; + private long framesToMove; private Point2D lastPoint; double oldTime; double newTime; double lastYValue = 0; double lastXValue = 0; - private double dx; - private double dy; private double pixelVelocityX; private double pixelVelocityY; private static final int expectedUpdateInterval = 200; @@ -118,8 +121,6 @@ public class BoatGroup extends Group{ teamNameObject.setLayoutY(teamNameObject.getLayoutY() + dy); velocityObject.setLayoutX(velocityObject.getLayoutX() + dx); velocityObject.setLayoutY(velocityObject.getLayoutY() + dy); - wake.setLayoutX(wake.getLayoutX() + dx); - wake.setLayoutY(wake.getLayoutY() + dy); } @@ -136,16 +137,18 @@ public class BoatGroup extends Group{ teamNameObject.setLayoutY(y); velocityObject.setLayoutX(x); velocityObject.setLayoutY(y); - wake.setLayoutX(x); - wake.setLayoutY(y); } public void rotateTo (double rotation) { boatPoly.getTransforms().setAll(new Rotate(rotation)); } - public void updatePosition () { - moveGroupBy(dx, dy); + public void move() { + moveGroupBy(xIncrement, yIncrement); + framesToMove = framesToMove - 1; + if (framesToMove <= 0){ + isStopped = true; + } } /** @@ -153,20 +156,32 @@ public class BoatGroup extends Group{ * @param newXValue The X co-ordinate the boat needs to move to. * @param newYValue The Y co-ordinate the boat needs to move to. * @param rotation Rotation to move graphics to. - * @param raceIds RaceID of the object to move. + * @param timeValid the time the position values are valid for */ - public void setDestination (double newXValue, double newYValue, double rotation, double groundSpeed, long raceIds) { - System.currentTimeMillis(); - moveTo(lastXValue, lastYValue, rotation); + public void setDestination (double newXValue, double newYValue, double rotation, double groundSpeed, long timeValid, double frameRate, long id) { + if (lastTimeValid == 0){ + lastTimeValid = timeValid - 200; + moveTo(newXValue, newYValue, rotation); + } - dx = (newXValue - lastXValue)/12; - dy = (newYValue - lastYValue)/12; - lastXValue = newXValue; - lastYValue = newYValue; + rotateTo(rotation); + framesToMove = Math.round((frameRate/(1000.0f/(timeValid-lastTimeValid)))); - boat.setVelocity(groundSpeed); - velocityObject.setText(String.format("%.2f m/s", boat.getVelocity())); + double dx = newXValue - boatPoly.getLayoutX(); + double dy = newYValue - boatPoly.getLayoutY(); + + xIncrement = dx/framesToMove; + yIncrement = dy/framesToMove; + + if (id == 106){ + System.out.println(framesToMove); + System.out.println("xIncrement = " + xIncrement); + } + + velocityObject.setText(String.format("%.2f m/s", groundSpeed)); + lastTimeValid = timeValid; + isStopped = false; } @@ -230,4 +245,8 @@ public class BoatGroup extends Group{ group.getChildren().addAll(wake, lineGroup); return group; } + + public boolean isStopped() { + return isStopped; + } } \ No newline at end of file diff --git a/src/main/java/seng302/server/messages/BoatLocationMessage.java b/src/main/java/seng302/server/messages/BoatLocationMessage.java index 6cf0739d..57f31dd6 100644 --- a/src/main/java/seng302/server/messages/BoatLocationMessage.java +++ b/src/main/java/seng302/server/messages/BoatLocationMessage.java @@ -44,7 +44,7 @@ public class BoatLocationMessage extends Message { public BoatLocationMessage(int sourceId, int sequenceNum, double latitude, double longitude, double heading, long boatSpeed){ boatSpeed /= 10; messageVersionNumber = 1; - time = System.currentTimeMillis() / 1000L; + time = System.currentTimeMillis(); this.sourceId = sourceId; this.sequenceNum = sequenceNum; this.deviceType = DeviceType.RACING_YACHT; From 95e353c14ee96d82f6c85019fd3375d887436a27 Mon Sep 17 00:00:00 2001 From: Peter Galloway Date: Wed, 17 May 2017 17:55:21 +1200 Subject: [PATCH 13/32] fixed initialization bug #story[923] --- src/main/java/seng302/controllers/CanvasController.java | 1 + src/main/java/seng302/controllers/Controller.java | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/src/main/java/seng302/controllers/CanvasController.java b/src/main/java/seng302/controllers/CanvasController.java index d2e7ce02..22096b58 100644 --- a/src/main/java/seng302/controllers/CanvasController.java +++ b/src/main/java/seng302/controllers/CanvasController.java @@ -188,6 +188,7 @@ public class CanvasController { } private void updateBoatGroup(BoatGroup boatGroup) { + System.out.println("StreamParser.boatPositions.size()2 = " + StreamParser.boatPositions.size()); PriorityBlockingQueue movementQueue = StreamParser.boatPositions.get(boatGroup.getRaceId()); // giving the movementQueue a 5 packet buffer to account for slightly out of order packets if (movementQueue.size() > 5){ diff --git a/src/main/java/seng302/controllers/Controller.java b/src/main/java/seng302/controllers/Controller.java index bebc57fd..00397dee 100644 --- a/src/main/java/seng302/controllers/Controller.java +++ b/src/main/java/seng302/controllers/Controller.java @@ -1,5 +1,7 @@ package seng302.controllers; +import static seng302.models.stream.StreamParser.boatPositions; + import javafx.application.Platform; import javafx.collections.FXCollections; import javafx.collections.ObservableList; @@ -131,6 +133,8 @@ public class Controller implements Initializable { public void switchToRaceView() { switchedToRaceView = true; setContentPane("/views/RaceView.fxml"); + System.out.println("boatPositions.size()1 = " + boatPositions.size()); + StreamParser.boatPositions.clear(); } private void updateTeamList() { From 2e375978bd345dad487d3d38ea4eec70f7df66fb Mon Sep 17 00:00:00 2001 From: Peter Galloway Date: Wed, 17 May 2017 19:18:31 +1200 Subject: [PATCH 14/32] cleaned up code for merging back to develop #story[923] --- .../seng302/controllers/CanvasController.java | 33 +------- .../java/seng302/controllers/Controller.java | 1 - .../controllers/RaceViewController.java | 1 - src/main/java/seng302/models/BoatGroup.java | 43 +---------- src/main/java/seng302/models/RaceObject.java | 75 ------------------- 5 files changed, 2 insertions(+), 151 deletions(-) delete mode 100644 src/main/java/seng302/models/RaceObject.java diff --git a/src/main/java/seng302/controllers/CanvasController.java b/src/main/java/seng302/controllers/CanvasController.java index 22096b58..26d7fec7 100644 --- a/src/main/java/seng302/controllers/CanvasController.java +++ b/src/main/java/seng302/controllers/CanvasController.java @@ -188,18 +188,12 @@ public class CanvasController { } private void updateBoatGroup(BoatGroup boatGroup) { - System.out.println("StreamParser.boatPositions.size()2 = " + StreamParser.boatPositions.size()); PriorityBlockingQueue movementQueue = StreamParser.boatPositions.get(boatGroup.getRaceId()); // giving the movementQueue a 5 packet buffer to account for slightly out of order packets - if (movementQueue.size() > 5){ + if (movementQueue.size() > 0){ try { BoatPositionPacket positionPacket = movementQueue.take(); Point2D p2d = findScaledXY(positionPacket.getLat(), positionPacket.getLon()); - if (boatGroup.getRaceId() == 106){ -// System.out.println("p2d.getX() = " + p2d.getX()); -// System.out.println("p2d.getY() = " + p2d.getY()); -// System.out.println("positionPacket.getTimeValid() = " + positionPacket.getTimeValid()); - } double heading = 360.0 / 0xffff * positionPacket.getHeading(); boatGroup.setDestination(p2d.getX(), p2d.getY(), heading, positionPacket.getGroundSpeed(), positionPacket.getTimeValid(), frameRate, boatGroup.getRaceId()); } catch (InterruptedException e){ @@ -389,31 +383,6 @@ public class CanvasController { return horiDistance; } - /** - * Give all markers in the course an x,y location relative to a given reference with a known x,y location. Distances - * are scaled according to the distanceScaleFactor variable. - */ - // DEPRECATED create an initialize marks method like the initialize boats method - private void givePointsXY() { -// List allPoints = StreamParser.getXmlObject().getRaceXML().getCompoundMarks(); -// List processed = new ArrayList<>(); -// MarkGroup markGroup; -// -// for (XMLParser.RaceXMLObject.CompoundMark mark : allPoints) { -// if (!processed.contains(mark)) { -// if (mark.getMarkType() != MarkType.SINGLE_MARK) { -// markGroup = new MarkGroup(mark, findScaledXY(mark.getMarks().get(0)), findScaledXY(mark.getMarks().get(1))); -// markGroups.add(markGroup); -// } else { -// markGroup = new MarkGroup(mark, findScaledXY(mark.getMarks().get(0))); -// markGroups.add(markGroup); -// } -// processed.add(mark); -// } -// } - group.getChildren().addAll(boatGroups); - } - private Point2D findScaledXY (Mark unscaled) { return findScaledXY (unscaled.getLatitude(), unscaled.getLongitude()); } diff --git a/src/main/java/seng302/controllers/Controller.java b/src/main/java/seng302/controllers/Controller.java index 00397dee..c27e6192 100644 --- a/src/main/java/seng302/controllers/Controller.java +++ b/src/main/java/seng302/controllers/Controller.java @@ -133,7 +133,6 @@ public class Controller implements Initializable { public void switchToRaceView() { switchedToRaceView = true; setContentPane("/views/RaceView.fxml"); - System.out.println("boatPositions.size()1 = " + boatPositions.size()); StreamParser.boatPositions.clear(); } diff --git a/src/main/java/seng302/controllers/RaceViewController.java b/src/main/java/seng302/controllers/RaceViewController.java index 8a09619e..85029772 100644 --- a/src/main/java/seng302/controllers/RaceViewController.java +++ b/src/main/java/seng302/controllers/RaceViewController.java @@ -25,7 +25,6 @@ import seng302.controllers.annotations.ImportantAnnotationController; import seng302.controllers.annotations.ImportantAnnotationDelegate; import seng302.controllers.annotations.ImportantAnnotationsState; import seng302.models.BoatGroup; -import seng302.models.RaceObject; import seng302.models.Yacht; import seng302.models.stream.StreamParser; diff --git a/src/main/java/seng302/models/BoatGroup.java b/src/main/java/seng302/models/BoatGroup.java index 3de6d3a8..0218a70b 100644 --- a/src/main/java/seng302/models/BoatGroup.java +++ b/src/main/java/seng302/models/BoatGroup.java @@ -1,16 +1,10 @@ package seng302.models; -import javafx.geometry.Point2D; import javafx.scene.Group; import javafx.scene.paint.Color; -import javafx.scene.shape.Line; import javafx.scene.shape.Polygon; import javafx.scene.text.Text; import javafx.scene.transform.Rotate; -import javafx.stage.Stage; - -import java.util.ArrayList; -import java.util.List; /** * BoatGroup is a javafx group that by default contains a graphical objects for representing a 2 dimensional boat. @@ -34,14 +28,6 @@ public class BoatGroup extends Group{ private double yIncrement; private long lastTimeValid = 0; private long framesToMove; - private Point2D lastPoint; - double oldTime; - double newTime; - double lastYValue = 0; - double lastXValue = 0; - private double pixelVelocityX; - private double pixelVelocityY; - private static final int expectedUpdateInterval = 200; //Graphical objects private Yacht boat; private Group lineGroup = new Group(); @@ -163,21 +149,12 @@ public class BoatGroup extends Group{ lastTimeValid = timeValid - 200; moveTo(newXValue, newYValue, rotation); } - - - rotateTo(rotation); framesToMove = Math.round((frameRate/(1000.0f/(timeValid-lastTimeValid)))); - double dx = newXValue - boatPoly.getLayoutX(); double dy = newYValue - boatPoly.getLayoutY(); - xIncrement = dx/framesToMove; yIncrement = dy/framesToMove; - - if (id == 106){ - System.out.println(framesToMove); - System.out.println("xIncrement = " + xIncrement); - } + rotateTo(rotation); velocityObject.setText(String.format("%.2f m/s", groundSpeed)); lastTimeValid = timeValid; @@ -186,10 +163,6 @@ public class BoatGroup extends Group{ - - - - public void setTeamNameObjectVisible(Boolean visible) { teamNameObject.setVisible(visible); } @@ -210,20 +183,6 @@ public class BoatGroup extends Group{ return boat; } -// /** -// * Returns true if this BoatGroup contains at least one of the given IDs. -// * -// * @param raceIds The ID's to check the BoatGroup for. -// * @return True if the BoatGroup contains at east one of the given IDs, false otherwise. -// */ -// public boolean hasRaceId (long... raceIds) { -// for (long id : raceIds) { -// if (id == boat.getSourceID()) -// return true; -// } -// return false; -// } - /** * Returns all raceIds associated with this group. For BoatGroups the ID's are for the boat. * diff --git a/src/main/java/seng302/models/RaceObject.java b/src/main/java/seng302/models/RaceObject.java deleted file mode 100644 index 706bfd48..00000000 --- a/src/main/java/seng302/models/RaceObject.java +++ /dev/null @@ -1,75 +0,0 @@ -package seng302.models; - -import javafx.geometry.Point2D; -import javafx.scene.Group; - -/** - * RaceObject defines the behaviour that animated objects whose position is updated from a yacht race data stream must - * adhere to. - */ -public abstract class RaceObject extends Group { - - //Time between sections of race - protected static double expectedUpdateInterval = 200; - - protected double rotationalGoal; - protected double currentRotation; - protected double rotationalVelocity; - protected double pixelVelocityX; - protected double pixelVelocityY; - - public Point2D getPosition () { - return new Point2D(super.getLayoutX(), getLayoutY()); - } - - public static double getExpectedUpdateInterval() { - return expectedUpdateInterval; - } - - /** - * - */ - public static void setExpectedUpdateInterval(double expectedUpdateInterval) { - RaceObject.expectedUpdateInterval = expectedUpdateInterval; - } - - /** - * Calculates the rotational velocity required to reach the rotationalGoal from the currentRotation. - */ - protected void calculateRotationalVelocity () { - if (Math.abs(rotationalGoal - currentRotation) > 180) { - if (rotationalGoal - currentRotation >= 0) { - this.rotationalVelocity = ((rotationalGoal - currentRotation) - 360) / expectedUpdateInterval; - } else { - this.rotationalVelocity = (360 + (rotationalGoal - currentRotation)) / expectedUpdateInterval; - } - } else { - this.rotationalVelocity = (rotationalGoal - currentRotation) / expectedUpdateInterval; - } - //Sometimes the rotation is too large to be realistic. In that case just do it instantly. -// if (Math.abs(rotationalVelocity) > 1) { -// rotationalVelocity = 0; -// rotateTo(rotationalGoal); -// } - } - - /** - * Sets the destination of everything within the RaceObject that has an ID in the array raceIds. The destination is - * set to the co-ordinates (x, y) with the given rotation. - * @param x X co-ordinate to move the graphics to. - * @param y Y co-ordinate to move the graphics to. - * @param rotation Rotation to move graphics to. - * @param raceIds RaceID of the object to move. - */ - public abstract void setDestination (double x, double y, double rotation, double groundSpeed, int... raceIds); - - public abstract void updatePosition (long timeInterval); - - public abstract void moveTo (double x, double y, double rotation); - - public abstract void moveGroupBy(double x, double y, double rotation); - - public abstract boolean hasRaceId (int... raceIds); - - public abstract int[] getRaceIds (); -} From 3fd13ddc0ae48626c56ed549ac35179a3f59e461 Mon Sep 17 00:00:00 2001 From: alistairjmcintyre Date: Wed, 17 May 2017 19:46:05 +1200 Subject: [PATCH 15/32] Adjusted XMLParser to use model Mark objects rather than the simple datatype that existed in the XMLParser previously. Began attempting to implement them into the canvas controller but have issues #[issue10] --- .../seng302/controllers/CanvasController.java | 36 +- src/main/java/seng302/models/mark/Mark.java | 1 - .../java/seng302/models/stream/XMLParser.java | 374 +++++++++++------- 3 files changed, 251 insertions(+), 160 deletions(-) diff --git a/src/main/java/seng302/controllers/CanvasController.java b/src/main/java/seng302/controllers/CanvasController.java index a2e00a23..6b34732d 100644 --- a/src/main/java/seng302/controllers/CanvasController.java +++ b/src/main/java/seng302/controllers/CanvasController.java @@ -125,7 +125,7 @@ public class CanvasController { // TODO: 1/05/17 cir27 - Make the RaceObjects update on the actual delay. elapsedNanos = 1000 / 60; - updateRaceObjects(); + //updateRaceObjects(); if (StreamParser.isRaceFinished()) { this.stop(); } @@ -423,23 +423,29 @@ public class CanvasController { * are scaled according to the distanceScaleFactor variable. */ private void givePointsXY() { - List allPoints = StreamParser.getXmlObject().getRaceXML().getCompoundMarks(); - List processed = new ArrayList<>(); - MarkGroup markGroup; + Map allPoints = StreamParser.getXmlObject().getRaceXML().getCompoundMarks(); + List processed = new ArrayList<>(); + MarkGroup markGroup; - for (XMLParser.RaceXMLObject.CompoundMark mark : allPoints) { - if (!processed.contains(mark)) { - if (mark.getMarkType() != MarkType.SINGLE_MARK) { - markGroup = new MarkGroup(mark, findScaledXY(mark.getMarks().get(0)), findScaledXY(mark.getMarks().get(1))); - markGroups.add(markGroup); - } else { - markGroup = new MarkGroup(mark, findScaledXY(mark.getMarks().get(0))); - markGroups.add(markGroup); + for (Map.Entry cMark : allPoints) { + Integer cMarkId = cMark.getKey(); + Mark mark = cMark.getValue(); + if (!processed.contains(mark)) { + if (mark.getMarkType() != MarkType.SINGLE_MARK) { + GateMark gMark = (GateMark) mark; + + markGroup = new MarkGroup(mark, findScaledXY(gMark.getSingleMark1()), findScaledXY(gMark.getSingleMark2())); //should be 2 objects in the list. + markGroups.add(markGroup); + } else { + SingleMark sMark = (SingleMark) mark; + + markGroup = new MarkGroup(mark, findScaledXY(sMark)); + markGroups.add(markGroup); + } + processed.add((mark)); } - processed.add(mark); } - } - group.getChildren().addAll(boatGroups); + group.getChildren().addAll(boatGroups); } private Point2D findScaledXY (Mark unscaled) { diff --git a/src/main/java/seng302/models/mark/Mark.java b/src/main/java/seng302/models/mark/Mark.java index a32ba20f..ce5a6f4a 100644 --- a/src/main/java/seng302/models/mark/Mark.java +++ b/src/main/java/seng302/models/mark/Mark.java @@ -132,5 +132,4 @@ public abstract class Mark { public void setId(int id) { this.id = id; } - } diff --git a/src/main/java/seng302/models/stream/XMLParser.java b/src/main/java/seng302/models/stream/XMLParser.java index 181c1e2f..43595cea 100644 --- a/src/main/java/seng302/models/stream/XMLParser.java +++ b/src/main/java/seng302/models/stream/XMLParser.java @@ -1,27 +1,30 @@ package seng302.models.stream; +import java.util.List; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import seng302.models.Yacht; +import seng302.models.mark.GateMark; +import seng302.models.mark.Mark; import seng302.models.mark.MarkType; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; +import seng302.models.mark.SingleMark; /** * Class to create an XML object from the XML Packet Messages. * * Example usage: * - * Document doc; // some xml document - * Integer xmlMessageType; // an Integer of value 5, 6, 7 - * - * xmlP = new XMLParser(doc, xmlMessageType); - * RegattaXMLObject rXmlObj = xmlP.createRegattaXML(); // creates a regattaXML object. + * Document doc; // some xml document + * Integer xmlMessageType; // an Integer of value 5, 6, 7 * + * xmlP = new XMLParser(doc, xmlMessageType); + * RegattaXMLObject rXmlObj = xmlP.createRegattaXML(); // creates a regattaXML object. */ public class XMLParser { @@ -31,10 +34,12 @@ public class XMLParser { private RegattaXMLObject regattaXML; private BoatXMLObject boatXML; - public XMLParser() {} + public XMLParser() { + } /** * Constructor for XMLParser + * * @param doc Document to create XML object. * @param messageType Defines if a message is a RegattaXML(5), RaceXML(6), BoatXML(7). */ @@ -53,13 +58,22 @@ public class XMLParser { } } - public RaceXMLObject getRaceXML() { return raceXML; } - public RegattaXMLObject getRegattaXML() { return regattaXML; } - public BoatXMLObject getBoatXML() { return boatXML; } + public RaceXMLObject getRaceXML() { + return raceXML; + } + + public RegattaXMLObject getRegattaXML() { + return regattaXML; + } + + public BoatXMLObject getBoatXML() { + return boatXML; + } /** * Returns the text content of a given child element tag, assuming it exists, as an Integer. + * * @param ele Document Element with child elements. * @param tag Tag to find in document elements child elements. * @return Text content from tag if found, null otherwise. @@ -75,6 +89,7 @@ public class XMLParser { /** * Returns the text content of a given child element tag, assuming it exists, as an String. + * * @param ele Document Element with child elements. * @param tag Tag to find in document elements child elements. * @return Text content from tag if found, null otherwise. @@ -90,6 +105,7 @@ public class XMLParser { /** * Returns the text content of a given child element tag, assuming it exists, as a Double. + * * @param ele Document Element with child elements. * @param tag Tag to find in document elements child elements. * @return Text content from tag if found, null otherwise. @@ -105,9 +121,11 @@ public class XMLParser { /** * Returns the text content of an attribute of a given Node, assuming it exists, as a String. + * * @param n A node object that should have some attributes * @param attr The attribute you want to get from the given node. - * @return The String representation of the text content of an attribute in the given node, else returns null. + * @return The String representation of the text content of an attribute in the given node, else + * returns null. */ private static String getNodeAttributeString(Node n, String attr) { Node attrItem = n.getAttributes().getNamedItem(attr); @@ -120,9 +138,11 @@ public class XMLParser { /** * Returns the text content of an attribute of a given Node, assuming it exists, as an Integer. + * * @param n A node object that should have some attributes * @param attr The attribute you want to get from the given node. - * @return The Integer representation of the text content of an attribute in the given node, else returns null. + * @return The Integer representation of the text content of an attribute in the given node, + * else returns null. */ private static Integer getNodeAttributeInt(Node n, String attr) { Node attrItem = n.getAttributes().getNamedItem(attr); @@ -135,9 +155,11 @@ public class XMLParser { /** * Returns the text content of an attribute of a given Node, assuming it exists, as a Double. + * * @param n A node object that should have some attributes * @param attr The attribute you want to get from the given node. - * @return The Double representation of the text content of an attribute in the given node, else returns null. + * @return The Double representation of the text content of an attribute in the given node, else + * returns null. */ private static Double getNodeAttributeDouble(Node n, String attr) { Node attrItem = n.getAttributes().getNamedItem(attr); @@ -149,6 +171,7 @@ public class XMLParser { } public class RegattaXMLObject { + //Regatta Info private Integer regattaID; private String regattaName; @@ -160,6 +183,7 @@ public class XMLParser { /** * Constructor for a RegattaXMLObject. * Takes the information from a Document object and creates a more usable format. + * * @param doc XML Document Object */ RegattaXMLObject(Document doc) { @@ -173,12 +197,29 @@ public class XMLParser { this.utcOffset = getElementInt(docEle, "UtcOffset"); } - public Integer getRegattaID() { return regattaID; } - public String getRegattaName() { return regattaName; } - public String getCourseName() { return courseName; } - public Double getCentralLat() { return centralLat; } - public Double getCentralLng() { return centralLng; } - public Integer getUtcOffset() { return utcOffset; } + public Integer getRegattaID() { + return regattaID; + } + + public String getRegattaName() { + return regattaName; + } + + public String getCourseName() { + return courseName; + } + + public Double getCentralLat() { + return centralLat; + } + + public Double getCentralLng() { + return centralLng; + } + + public Integer getUtcOffset() { + return utcOffset; + } } @@ -195,13 +236,14 @@ public class XMLParser { //Non atomic race attributes private ArrayList participants; - private ArrayList course; + private Map course; private ArrayList compoundMarkSequence; private ArrayList courseLimit; /** * Constructor for a RaceXMLObject. * Takes the information from a Document object and creates a more usable format. + * * @param doc XML Document Object */ RaceXMLObject(Document doc) { @@ -213,8 +255,9 @@ public class XMLParser { this.creationTimeDate = getElementString(docEle, "CreationTimeDate"); Node raceStart = docEle.getElementsByTagName("RaceStartTime").item(0); - this.raceStartTime = getNodeAttributeString(raceStart, "Start") ; - this.postponeStatus = Boolean.parseBoolean(getNodeAttributeString(raceStart, "Postpone")); + this.raceStartTime = getNodeAttributeString(raceStart, "Start"); + this.postponeStatus = Boolean + .parseBoolean(getNodeAttributeString(raceStart, "Postpone")); //Participants participants = new ArrayList<>(); @@ -238,21 +281,13 @@ public class XMLParser { } //Course - course = new ArrayList<>(); - - NodeList cMarkList = docEle.getElementsByTagName("Course").item(0).getChildNodes(); - for (int i = 0; i < cMarkList.getLength(); i++) { - Node cMarkNode = cMarkList.item(i); - if (cMarkNode.getNodeName().equals("CompoundMark")) { - CompoundMark cMark = new CompoundMark(cMarkNode); - course.add(cMark); - } - } + course = createCompoundMarks(docEle); //Course Mark Sequence compoundMarkSequence = new ArrayList<>(); - NodeList cornerList = docEle.getElementsByTagName("CompoundMarkSequence").item(0).getChildNodes(); + NodeList cornerList = docEle.getElementsByTagName("CompoundMarkSequence").item(0) + .getChildNodes(); for (int i = 0; i < cornerList.getLength(); i++) { Node cornerNode = cornerList.item(i); if (cornerNode.getNodeName().equals("Corner")) { @@ -274,18 +309,97 @@ public class XMLParser { } } - public Integer getRaceID() { return raceID; } - public String getRaceType() { return raceType; } - public String getCreationTimeDate() { return creationTimeDate; } - public String getRaceStartTime() { return raceStartTime; } - public Boolean getPostponeStatus() { return postponeStatus; } - public ArrayList getParticipants() { return participants; } - public ArrayList getCompoundMarks() { return course; } - public ArrayList getCompoundMarkSequence() { return compoundMarkSequence; } - public ArrayList getCourseLimit() { return courseLimit; } + private Map createCompoundMarks(Element docEle) { + Map cMarks = new HashMap<>(); + + NodeList cMarkList = docEle.getElementsByTagName("Course").item(0).getChildNodes(); + for (int i = 0; i < cMarkList.getLength(); i++) { + Node cMarkNode = cMarkList.item(i); + + if (cMarkNode.getNodeName().equals("CompoundMark")) { + Integer markID = getNodeAttributeInt(cMarkNode, "CompoundMarkID"); + Mark mark = createMark(cMarkNode); + + cMarks.put(markID, mark); + } + } + + return cMarks; + } + + private Mark createMark(Node compoundMark) { + + List marksList = new ArrayList<>(); + String cMarkName = getNodeAttributeString(compoundMark, "Name"); + + NodeList childMarks = compoundMark.getChildNodes(); + + for (int i = 0; i < childMarks.getLength(); i++) { + Node markNode = childMarks.item(i); + if (markNode.getNodeName().equals("Mark")) { + + Integer sourceID = getNodeAttributeInt(markNode, "SourceID"); + String markName = getNodeAttributeString(markNode, "Name"); + Double targetLat = getNodeAttributeDouble(markNode, "TargetLat"); + Double targetLng = getNodeAttributeDouble(markNode, "TargetLng"); + + SingleMark mark = new SingleMark(markName, targetLat, targetLng, sourceID); + marksList.add(mark); + } + } + + System.out.println(marksList.size()); + if (marksList.size() == 1) { + return marksList.get(0); + } else if (marksList.size() == 2) { + return new GateMark(cMarkName, MarkType.OPEN_GATE, marksList.get(0), + marksList.get(1), marksList.get(0).getLatitude(), + marksList.get(0).getLongitude()); + } else { + return null; + } + + } + + public Integer getRaceID() { + return raceID; + } + + public String getRaceType() { + return raceType; + } + + public String getCreationTimeDate() { + return creationTimeDate; + } + + public String getRaceStartTime() { + return raceStartTime; + } + + public Boolean getPostponeStatus() { + return postponeStatus; + } + + public ArrayList getParticipants() { + return participants; + } + + public Map getCompoundMarks() { + return course; + } + + public ArrayList getCompoundMarkSequence() { + return compoundMarkSequence; + } + + public ArrayList getCourseLimit() { + return courseLimit; + } public class Participant { + Integer sourceID; String entry; @@ -294,65 +408,17 @@ public class XMLParser { this.entry = entry; } - public Integer getsourceID() { return sourceID; } - public String getEntry() { return entry; } - } - - public class CompoundMark { - private Integer markID; - private String cMarkName; - private MarkType markType; - private ArrayList marks; - - CompoundMark(Node compoundMark) { - marks = new ArrayList<>(); - this.markID = getNodeAttributeInt(compoundMark, "CompoundMarkID"); - this.cMarkName = getNodeAttributeString(compoundMark, "Name"); - NodeList childMarks = compoundMark.getChildNodes(); - if (childMarks.getLength() > 1){ - markType = MarkType.OPEN_GATE; - } else { - markType = MarkType.SINGLE_MARK; - } - - for (int i = 0; i < childMarks.getLength(); i++) { - Node markNode = childMarks.item(i); - if (markNode.getNodeName().equals("Mark")) { - Mark mark = new Mark(markNode); - marks.add(mark); - } - } + public Integer getsourceID() { + return sourceID; } - public Integer getMarkID() { return markID; } - public String getcMarkName() { return cMarkName; } - public MarkType getMarkType() { return markType; } - public ArrayList getMarks() { return marks; } - - public class Mark { - private Integer seqID; - private Integer sourceID; - private String markName; - private Double targetLat; - private Double targetLng; - - Mark(Node markNode) { - this.seqID = getNodeAttributeInt(markNode, "SeqID"); - this.sourceID = getNodeAttributeInt(markNode, "SourceID"); - this.markName = getNodeAttributeString(markNode, "Name"); - this.targetLat = getNodeAttributeDouble(markNode, "TargetLat"); - this.targetLng = getNodeAttributeDouble(markNode, "TargetLng"); - } - - public Integer getSeqID() { return seqID; } - public Integer getSourceID() { return sourceID; } - public String getMarkName() { return markName; } - public Double getTargetLat() { return targetLat; } - public Double getTargetLng() { return targetLng; } + public String getEntry() { + return entry; } } public class Corner { + private Integer seqID; private Integer compoundMarkID; private String rounding; @@ -365,13 +431,25 @@ public class XMLParser { this.zoneSize = getNodeAttributeInt(cornerNode, "ZoneSize"); } - public Integer getSeqID() { return seqID; } - public Integer getCompoundMarkID() { return compoundMarkID; } - public String getRounding() { return rounding; } - public Integer getZoneSize() { return zoneSize; } + public Integer getSeqID() { + return seqID; + } + + public Integer getCompoundMarkID() { + return compoundMarkID; + } + + public String getRounding() { + return rounding; + } + + public Integer getZoneSize() { + return zoneSize; + } } public class Limit { + private Integer seqID; private Double lat; private Double lng; @@ -382,9 +460,17 @@ public class XMLParser { this.lng = getNodeAttributeDouble(limitNode, "Lon"); } - public Integer getSeqID() { return seqID; } - public Double getLat() { return lat; } - public Double getLng() { return lng; } + public Integer getSeqID() { + return seqID; + } + + public Double getLat() { + return lat; + } + + public Double getLng() { + return lng; + } } } @@ -410,6 +496,7 @@ public class XMLParser { /** * Constructor for a BoatXMLObject. * Takes the information from a Document object and creates a more usable format. + * * @param doc XML Document Object */ BoatXMLObject(Document doc) { @@ -429,7 +516,7 @@ public class XMLParser { Node zoneLimitsList = settingsList.item(7); this.zoneLimits = new ArrayList<>(); for (int i = 0; i < zoneLimitsList.getAttributes().getLength(); i++) { - String tag = String.format("Limit%d", i+1); + String tag = String.format("Limit%d", i + 1); this.zoneLimits.add(getNodeAttributeDouble(zoneLimitsList, tag)); } @@ -440,61 +527,60 @@ public class XMLParser { if (currentBoat.getNodeName().equals("Boat")) { // Boat boat = new Boat(currentBoat); Yacht boat = new Yacht(getNodeAttributeString(currentBoat, "Type"), - getNodeAttributeInt(currentBoat, "SourceID"), - getNodeAttributeString(currentBoat, "HullNum"), - getNodeAttributeString(currentBoat, "ShortName"), - getNodeAttributeString(currentBoat, "BoatName"), - getNodeAttributeString(currentBoat, "Country")); + getNodeAttributeInt(currentBoat, "SourceID"), + getNodeAttributeString(currentBoat, "HullNum"), + getNodeAttributeString(currentBoat, "ShortName"), + getNodeAttributeString(currentBoat, "BoatName"), + getNodeAttributeString(currentBoat, "Country")); this.boats.add(boat); if (boat.getBoatType().equals("Yacht")) { competingBoats.put(boat.getSourceID(), boat); } } - //System.out.println(this.getBoats()); } } - public String getLastModified() { return lastModified; } - public Integer getVersion() { return version; } - public String getBoatType() { return boatType; } - public Double getBoatLength() { return boatLength; } - public Double getHullLength() { return hullLength; } - public Double getMarkZoneSize() { return markZoneSize; } - public Double getCourseZoneSize() { return courseZoneSize; } - public ArrayList getZoneLimits() { return zoneLimits; } - public ArrayList getBoats() { return boats; } + public String getLastModified() { + return lastModified; + } + + public Integer getVersion() { + return version; + } + + public String getBoatType() { + return boatType; + } + + public Double getBoatLength() { + return boatLength; + } + + public Double getHullLength() { + return hullLength; + } + + public Double getMarkZoneSize() { + return markZoneSize; + } + + public Double getCourseZoneSize() { + return courseZoneSize; + } + + public ArrayList getZoneLimits() { + return zoneLimits; + } + + public ArrayList getBoats() { + return boats; + } + public Map getCompetingBoats() { return competingBoats; } -// public class Boat { -// -// private String boatType; -// private Integer sourceID; -// private String hullID; //matches HullNum in the XML spec. -// private String shortName; -// private String boatName; -// private String country; -// -// Boat(Node boatNode) { -// this.boatType = getNodeAttributeString(boatNode, "Type"); -// this.sourceID = getNodeAttributeInt(boatNode, "SourceID"); -// this.hullID = getNodeAttributeString(boatNode, "HullNum"); -// this.shortName = getNodeAttributeString(boatNode, "ShortName"); -// this.boatName = getNodeAttributeString(boatNode, "BoatName"); -// this.country = getNodeAttributeString(boatNode, "Country"); -// } -// -// public String getBoatType() { return boatType; } -// public Integer getSourceID() { return sourceID; } -// public String getHullID() { return hullID; } -// public String getShortName() { return shortName; } -// public String getBoatName() { return boatName; } -// public String getCountry() { return country; } -// -// } - } } \ No newline at end of file From 0f79353936aee8ac7110ece2755746dc0af0131c Mon Sep 17 00:00:00 2001 From: Peter Galloway Date: Wed, 17 May 2017 20:15:47 +1200 Subject: [PATCH 16/32] fixes from merge #story[923] --- .../controllers/RaceViewController.java | 103 +++++++----------- .../controllers/StartScreenController.java | 2 +- .../seng302/models/stream/StreamParser.java | 7 +- 3 files changed, 44 insertions(+), 68 deletions(-) diff --git a/src/main/java/seng302/controllers/RaceViewController.java b/src/main/java/seng302/controllers/RaceViewController.java index 22c96f13..b00963be 100644 --- a/src/main/java/seng302/controllers/RaceViewController.java +++ b/src/main/java/seng302/controllers/RaceViewController.java @@ -26,7 +26,7 @@ import seng302.controllers.annotations.ImportantAnnotationController; import seng302.controllers.annotations.ImportantAnnotationDelegate; import seng302.controllers.annotations.ImportantAnnotationsState; import seng302.models.*; -import seng302.models.parsers.StreamParser; +import seng302.models.stream.StreamParser; import java.io.IOException; import java.util.*; @@ -58,7 +58,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel private ArrayList startingBoats = new ArrayList<>(); private boolean displayFps; private Timeline timerTimeline; - private Race race; private Stage stage; private ImportantAnnotationsState importantAnnotations; @@ -68,13 +67,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel // Load a default important annotation state importantAnnotations = new ImportantAnnotationsState(); - //Initialise race controller - RaceController raceController = new RaceController(); - raceController.initializeRace(); - race = raceController.getRace(); - - startingBoats = new ArrayList<>(Arrays.asList(race.getBoats())); - includedCanvasController.setup(this); includedCanvasController.initializeCanvas(); initializeUpdateTimer(); @@ -282,7 +274,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel */ private void loadRaceResultView() { FXMLLoader loader = new FXMLLoader(getClass().getResource("/views/FinishView.fxml")); - loader.setController(new RaceResultController(race)); try { contentAnchorPane.getChildren().removeAll(); @@ -335,11 +326,6 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel return displayFps; } - public Race getRace() { - return race; - } - - /** * Display the important annotations for a specific BoatGroup * @param bg The boat group to set the annotations for @@ -368,57 +354,48 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel } else { bg.setWakeVisible(false); } - - if (importantAnnotations.getAnnotationState(Annotation.ESTTIMETONEXTMARK)) { - bg.setEstTimeToNextMarkObjectVisible(true); - } else { - bg.setEstTimeToNextMarkObjectVisible(false); - } - - if (importantAnnotations.getAnnotationState(Annotation.LEGTIME)) { - bg.setLegTimeObjectVisible(true); - } else { - bg.setLegTimeObjectVisible(false); - } + //TODO fix boat annotations with new boatgroup +// if (importantAnnotations.getAnnotationState(Annotation.ESTTIMETONEXTMARK)) { +// bg.setEstTimeToNextMarkObjectVisible(true); +// } else { +// bg.setEstTimeToNextMarkObjectVisible(false); +// } +// +// if (importantAnnotations.getAnnotationState(Annotation.LEGTIME)) { +// bg.setLegTimeObjectVisible(true); +// } else { +// bg.setLegTimeObjectVisible(false); +// } } private void setAnnotations(Integer annotationLevel) { switch (annotationLevel) { // No Annotations case 0: - for (RaceObject ro : includedCanvasController.getRaceObjects()) { - if (ro instanceof BoatGroup) { - BoatGroup bg = (BoatGroup) ro; - bg.setTeamNameObjectVisible(false); - bg.setVelocityObjectVisible(false); - bg.setEstTimeToNextMarkObjectVisible(false); - bg.setLegTimeObjectVisible(false); - bg.setLineGroupVisible(false); - bg.setWakeVisible(false); - } + for (BoatGroup bg : includedCanvasController.getBoatGroups()) { + bg.setTeamNameObjectVisible(false); + bg.setVelocityObjectVisible(false); +// bg.setEstTimeToNextMarkObjectVisible(false); +// bg.setLegTimeObjectVisible(false); + bg.setLineGroupVisible(false); + bg.setWakeVisible(false); } break; // Important Annotations case 1: - for (RaceObject ro : includedCanvasController.getRaceObjects()) { - if (ro instanceof BoatGroup) { - BoatGroup bg = (BoatGroup) ro; - setBoatGroupImportantAnnotations(bg); - } + for (BoatGroup bg : includedCanvasController.getBoatGroups()) { + setBoatGroupImportantAnnotations(bg); } break; // All Annotations case 2: - for (RaceObject ro : includedCanvasController.getRaceObjects()) { - if (ro instanceof BoatGroup) { - BoatGroup bg = (BoatGroup) ro; - bg.setTeamNameObjectVisible(true); - bg.setVelocityObjectVisible(true); - bg.setEstTimeToNextMarkObjectVisible(true); - bg.setLegTimeObjectVisible(true); - bg.setLineGroupVisible(true); - bg.setWakeVisible(true); - } + for (BoatGroup bg : includedCanvasController.getBoatGroups()) { + bg.setTeamNameObjectVisible(true); + bg.setVelocityObjectVisible(true); +// bg.setEstTimeToNextMarkObjectVisible(true); +// bg.setLegTimeObjectVisible(true); + bg.setLineGroupVisible(true); + bg.setWakeVisible(true); } break; } @@ -431,18 +408,16 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel * @param yacht The yacht for which we want to view all annotations */ private void setSelectedBoat(Yacht yacht) { - for (RaceObject ro : includedCanvasController.getRaceObjects()) { - if (ro instanceof BoatGroup) { - BoatGroup bg = (BoatGroup) ro; - //We need to iterate over all race groups to get the matching boat group belonging to this boat if we - //are to toggle its annotations, there is no other backwards knowledge of a yacht to its boatgroup. - if (bg.getBoat().getHullID().equals(yacht.getHullID())) { - bg.setIsSelected(true); - selectedBoat = yacht; - } else { - bg.setIsSelected(false); - } - } + for (BoatGroup bg : includedCanvasController.getBoatGroups()) { + //We need to iterate over all race groups to get the matching boat group belonging to this boat if we + //are to toggle its annotations, there is no other backwards knowledge of a yacht to its boatgroup. + //TODO fix boat selection with new boatgroup +// if (bg.getBoat().getHullID().equals(yacht.getHullID())) { +// bg.setIsSelected(true); +// selectedBoat = yacht; +// } else { +// bg.setIsSelected(false); +// } } } diff --git a/src/main/java/seng302/controllers/StartScreenController.java b/src/main/java/seng302/controllers/StartScreenController.java index 8a4d563b..94851d05 100644 --- a/src/main/java/seng302/controllers/StartScreenController.java +++ b/src/main/java/seng302/controllers/StartScreenController.java @@ -22,7 +22,7 @@ import javafx.scene.layout.GridPane; import javafx.scene.layout.Pane; import javafx.scene.paint.Color; import seng302.models.Yacht; -import seng302.models.parsers.StreamParser; +import seng302.models.stream.StreamParser; public class StartScreenController implements Initializable { @FXML diff --git a/src/main/java/seng302/models/stream/StreamParser.java b/src/main/java/seng302/models/stream/StreamParser.java index b6f0f0be..f7093306 100644 --- a/src/main/java/seng302/models/stream/StreamParser.java +++ b/src/main/java/seng302/models/stream/StreamParser.java @@ -1,12 +1,12 @@ -package seng302.models.parsers; +package seng302.models.stream; import org.w3c.dom.Document; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import seng302.models.Yacht; -import seng302.models.parsers.packets.BoatPositionPacket; -import seng302.models.parsers.packets.StreamPacket; +import seng302.models.stream.packets.BoatPositionPacket; +import seng302.models.stream.packets.StreamPacket; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; @@ -19,6 +19,7 @@ import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentSkipListMap; import java.util.concurrent.PriorityBlockingQueue; +import seng302.models.stream.XMLParser; /** * The purpose of this class is to take in the stream of divided packets so they can be read From a2123df0c5311b81a94a603081119ad79311aaa6 Mon Sep 17 00:00:00 2001 From: William Muir Date: Thu, 18 May 2017 14:41:08 +1200 Subject: [PATCH 17/32] Fixed Boat selection and lost annotations (Estimated and Leg Time) Trails and Wakes, however, are still not re implemented yet. story[923] --- .../controllers/RaceViewController.java | 43 +++++----- src/main/java/seng302/models/BoatGroup.java | 86 ++++++++++++++++++- 2 files changed, 104 insertions(+), 25 deletions(-) diff --git a/src/main/java/seng302/controllers/RaceViewController.java b/src/main/java/seng302/controllers/RaceViewController.java index b00963be..8492015b 100644 --- a/src/main/java/seng302/controllers/RaceViewController.java +++ b/src/main/java/seng302/controllers/RaceViewController.java @@ -355,17 +355,17 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel bg.setWakeVisible(false); } //TODO fix boat annotations with new boatgroup -// if (importantAnnotations.getAnnotationState(Annotation.ESTTIMETONEXTMARK)) { -// bg.setEstTimeToNextMarkObjectVisible(true); -// } else { -// bg.setEstTimeToNextMarkObjectVisible(false); -// } -// -// if (importantAnnotations.getAnnotationState(Annotation.LEGTIME)) { -// bg.setLegTimeObjectVisible(true); -// } else { -// bg.setLegTimeObjectVisible(false); -// } + if (importantAnnotations.getAnnotationState(Annotation.ESTTIMETONEXTMARK)) { + bg.setEstTimeToNextMarkObjectVisible(true); + } else { + bg.setEstTimeToNextMarkObjectVisible(false); + } + + if (importantAnnotations.getAnnotationState(Annotation.LEGTIME)) { + bg.setLegTimeObjectVisible(true); + } else { + bg.setLegTimeObjectVisible(false); + } } private void setAnnotations(Integer annotationLevel) { @@ -375,8 +375,8 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel for (BoatGroup bg : includedCanvasController.getBoatGroups()) { bg.setTeamNameObjectVisible(false); bg.setVelocityObjectVisible(false); -// bg.setEstTimeToNextMarkObjectVisible(false); -// bg.setLegTimeObjectVisible(false); + bg.setEstTimeToNextMarkObjectVisible(false); + bg.setLegTimeObjectVisible(false); bg.setLineGroupVisible(false); bg.setWakeVisible(false); } @@ -392,8 +392,8 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel for (BoatGroup bg : includedCanvasController.getBoatGroups()) { bg.setTeamNameObjectVisible(true); bg.setVelocityObjectVisible(true); -// bg.setEstTimeToNextMarkObjectVisible(true); -// bg.setLegTimeObjectVisible(true); + bg.setEstTimeToNextMarkObjectVisible(true); + bg.setLegTimeObjectVisible(true); bg.setLineGroupVisible(true); bg.setWakeVisible(true); } @@ -411,13 +411,12 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel for (BoatGroup bg : includedCanvasController.getBoatGroups()) { //We need to iterate over all race groups to get the matching boat group belonging to this boat if we //are to toggle its annotations, there is no other backwards knowledge of a yacht to its boatgroup. - //TODO fix boat selection with new boatgroup -// if (bg.getBoat().getHullID().equals(yacht.getHullID())) { -// bg.setIsSelected(true); -// selectedBoat = yacht; -// } else { -// bg.setIsSelected(false); -// } + if (bg.getBoat().getHullID().equals(yacht.getHullID())) { + bg.setIsSelected(true); + selectedBoat = yacht; + } else { + bg.setIsSelected(false); + } } } diff --git a/src/main/java/seng302/models/BoatGroup.java b/src/main/java/seng302/models/BoatGroup.java index 0218a70b..28e9561f 100644 --- a/src/main/java/seng302/models/BoatGroup.java +++ b/src/main/java/seng302/models/BoatGroup.java @@ -1,10 +1,18 @@ package seng302.models; +import javafx.event.EventHandler; +import javafx.scene.CacheHint; import javafx.scene.Group; +import javafx.scene.input.MouseDragEvent; +import javafx.scene.input.MouseEvent; import javafx.scene.paint.Color; import javafx.scene.shape.Polygon; import javafx.scene.text.Text; import javafx.scene.transform.Rotate; +import seng302.models.stream.StreamParser; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; /** * BoatGroup is a javafx group that by default contains a graphical objects for representing a 2 dimensional boat. @@ -17,9 +25,13 @@ public class BoatGroup extends Group{ //Constants for drawing private static final double TEAMNAME_X_OFFSET = 10d; - private static final double TEAMNAME_Y_OFFSET = -15d; + private static final double TEAMNAME_Y_OFFSET = -29d; private static final double VELOCITY_X_OFFSET = 10d; - private static final double VELOCITY_Y_OFFSET = -5d; + private static final double VELOCITY_Y_OFFSET = -17d; + private static final double ESTTIMETONEXTMARK_X_OFFSET = 10d; + private static final double ESTTIMETONEXTMARK_Y_OFFSET = -5d; + private static final double LEGTIME_X_OFFSET = 10d; + private static final double LEGTIME_Y_OFFSET = 7d; private static final double BOAT_HEIGHT = 15d; private static final double BOAT_WIDTH = 10d; //Variables for boat logic. @@ -34,8 +46,12 @@ public class BoatGroup extends Group{ private Polygon boatPoly; private Text teamNameObject; private Text velocityObject; + private Text estTimeToNextMarkObject; + private Text legTimeObject; private Wake wake; + private Boolean isSelected = true; //All boats are initalised as selected + /** * Creates a BoatGroup with the default triangular boat polygon. * @param boat The boat that the BoatGroup will represent. Must contain an ID which will be used to tell which @@ -68,9 +84,30 @@ public class BoatGroup extends Group{ private void initChildren (Color color, double... points) { boatPoly = new Polygon(points); boatPoly.setFill(color); + boatPoly.setOnMouseEntered(event -> boatPoly.setFill(Color.FLORALWHITE)); + boatPoly.setOnMouseExited(event -> boatPoly.setFill(color)); + boatPoly.setOnMouseClicked(event -> setIsSelected(!isSelected)); + boatPoly.setCache(true); + boatPoly.setCacheHint(CacheHint.SPEED); + teamNameObject = new Text(boat.getShortName()); + teamNameObject.setCache(true); + teamNameObject.setCacheHint(CacheHint.SPEED); velocityObject = new Text(String.valueOf(boat.getVelocity())); + DateFormat format = new SimpleDateFormat("mm:ss"); + String timeToNextMark = format + .format(boat.getEstimateTimeAtNextMark() - StreamParser.getCurrentTimeLong()); + estTimeToNextMarkObject = new Text("Next mark: " + timeToNextMark); + if (boat.getMarkRoundingTime() != null) { + String elapsedTime = format + .format(StreamParser.getCurrentTimeLong() - boat.getMarkRoundingTime()); + legTimeObject = new Text("Last mark: " + elapsedTime); + } else { + legTimeObject = new Text("Last mark: -"); + } + velocityObject.setCache(true); + velocityObject.setCacheHint(CacheHint.SPEED); teamNameObject.setX(TEAMNAME_X_OFFSET); teamNameObject.setY(TEAMNAME_Y_OFFSET); @@ -80,8 +117,19 @@ public class BoatGroup extends Group{ velocityObject.setY(VELOCITY_Y_OFFSET); velocityObject.relocate(velocityObject.getX(), velocityObject.getY()); + estTimeToNextMarkObject.setX(ESTTIMETONEXTMARK_X_OFFSET); + estTimeToNextMarkObject.setY(ESTTIMETONEXTMARK_Y_OFFSET); + estTimeToNextMarkObject + .relocate(estTimeToNextMarkObject.getX(), estTimeToNextMarkObject.getY()); + + legTimeObject.setX(LEGTIME_X_OFFSET); + legTimeObject.setY(LEGTIME_Y_OFFSET); + legTimeObject.relocate(legTimeObject.getX(), legTimeObject.getY()); + wake = new Wake(0, -BOAT_HEIGHT); - super.getChildren().addAll(teamNameObject, velocityObject, boatPoly); + super.getChildren() + .addAll(teamNameObject, velocityObject, boatPoly, estTimeToNextMarkObject, + legTimeObject); } /** @@ -107,6 +155,10 @@ public class BoatGroup extends Group{ teamNameObject.setLayoutY(teamNameObject.getLayoutY() + dy); velocityObject.setLayoutX(velocityObject.getLayoutX() + dx); velocityObject.setLayoutY(velocityObject.getLayoutY() + dy); + estTimeToNextMarkObject.setLayoutX(estTimeToNextMarkObject.getLayoutX() + dx); + estTimeToNextMarkObject.setLayoutY(estTimeToNextMarkObject.getLayoutY() + dy); + legTimeObject.setLayoutX(legTimeObject.getLayoutX() + dx); + legTimeObject.setLayoutY(legTimeObject.getLayoutY() + dy); } @@ -123,6 +175,10 @@ public class BoatGroup extends Group{ teamNameObject.setLayoutY(y); velocityObject.setLayoutX(x); velocityObject.setLayoutY(y); + estTimeToNextMarkObject.setLayoutX(x); + estTimeToNextMarkObject.setLayoutY(y); + legTimeObject.setLayoutX(x); + legTimeObject.setLayoutY(y); } public void rotateTo (double rotation) { @@ -162,6 +218,17 @@ public class BoatGroup extends Group{ } + public void setIsSelected(Boolean isSelected) { + this.isSelected = isSelected; + setTeamNameObjectVisible(isSelected); + setVelocityObjectVisible(isSelected); + setLineGroupVisible(isSelected); + setWakeVisible(isSelected); + setEstTimeToNextMarkObjectVisible(isSelected); + setLegTimeObjectVisible(isSelected); + } + + public void setTeamNameObjectVisible(Boolean visible) { teamNameObject.setVisible(visible); @@ -171,6 +238,14 @@ public class BoatGroup extends Group{ velocityObject.setVisible(visible); } + public void setEstTimeToNextMarkObjectVisible(Boolean visible) { + estTimeToNextMarkObject.setVisible(visible); + } + + public void setLegTimeObjectVisible(Boolean visible) { + legTimeObject.setVisible(visible); + } + public void setLineGroupVisible(Boolean visible) { lineGroup.setVisible(visible); } @@ -208,4 +283,9 @@ public class BoatGroup extends Group{ public boolean isStopped() { return isStopped; } + + @Override + public String toString() { + return boat.toString(); + } } \ No newline at end of file From 5d6b356602a993d592e82057dc2030bf6987d033 Mon Sep 17 00:00:00 2001 From: Alistair McIntyre Date: Thu, 18 May 2017 18:02:25 +1200 Subject: [PATCH 18/32] all marks displaying except currently gate marks are displaying as a single dot #story[923] #pair[ajm412, ptg19] --- src/main/java/seng302/App.java | 2 +- .../seng302/controllers/CanvasController.java | 51 +++++++++++++++---- src/main/java/seng302/models/mark/Mark.java | 4 +- .../java/seng302/models/mark/MarkGroup.java | 12 ++--- .../seng302/models/stream/StreamParser.java | 45 +++++++++++----- .../java/seng302/models/stream/XMLParser.java | 8 ++- 6 files changed, 83 insertions(+), 39 deletions(-) diff --git a/src/main/java/seng302/App.java b/src/main/java/seng302/App.java index ac264db6..28d7e923 100644 --- a/src/main/java/seng302/App.java +++ b/src/main/java/seng302/App.java @@ -63,7 +63,7 @@ public class App extends Application { //Change the StreamReceiver in this else block to change the default data source. else{ // sr = new StreamReceiver("localhost", 4949, "RaceStream"); - sr = new StreamReceiver("livedata.americascup.com", 4941, "RaceStream"); + sr = new StreamReceiver("csse-s302staff.canterbury.ac.nz", 4941, "RaceStream"); } sr.start(); diff --git a/src/main/java/seng302/controllers/CanvasController.java b/src/main/java/seng302/controllers/CanvasController.java index ff7a294f..c7fbcb6e 100644 --- a/src/main/java/seng302/controllers/CanvasController.java +++ b/src/main/java/seng302/controllers/CanvasController.java @@ -1,6 +1,11 @@ package seng302.controllers; -import javafx.animation.*; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.concurrent.PriorityBlockingQueue; +import javafx.animation.AnimationTimer; import javafx.beans.property.SimpleDoubleProperty; import javafx.fxml.FXML; import javafx.geometry.Point2D; @@ -10,15 +15,18 @@ import javafx.scene.canvas.GraphicsContext; import javafx.scene.layout.AnchorPane; import javafx.scene.paint.Color; import javafx.scene.text.Font; -import seng302.models.*; -import seng302.models.mark.*; +import seng302.models.BoatGroup; +import seng302.models.Colors; +import seng302.models.Yacht; +import seng302.models.mark.GateMark; +import seng302.models.mark.Mark; +import seng302.models.mark.MarkGroup; +import seng302.models.mark.MarkType; +import seng302.models.mark.SingleMark; import seng302.models.stream.StreamParser; -import seng302.models.stream.packets.BoatPositionPacket; import seng302.models.stream.XMLParser; import seng302.models.stream.XMLParser.RaceXMLObject.Limit; -import seng302.models.mark.Mark; -import java.util.*; -import java.util.concurrent.PriorityBlockingQueue; +import seng302.models.stream.packets.BoatPositionPacket; /** * Created by ptg19 on 15/03/17. @@ -96,6 +104,7 @@ public class CanvasController { // TODO: 1/05/17 wmu16 - Change this call to now draw the marks as from the xml initializeBoats(); + initializeMarks(); timer = new AnimationTimer() { @Override @@ -179,8 +188,8 @@ public class CanvasController { boatGroup.move(); } for (MarkGroup markGroup : markGroups) { - for (int id : markGroup.getRaceIds()) { - if (StreamParser.boatPositions.containsKey(id)) { + for (long id : markGroup.getRaceIds()) { + if (StreamParser.markPositions.containsKey(id)) { UpdateMarkGroup(id, markGroup); } } @@ -214,8 +223,8 @@ public class CanvasController { } } - void UpdateMarkGroup (int raceId, MarkGroup markGroup) { - PriorityBlockingQueue movementQueue = StreamParser.boatPositions.get(raceId); + void UpdateMarkGroup (long raceId, MarkGroup markGroup) { + PriorityBlockingQueue movementQueue = StreamParser.markPositions.get(raceId); if (movementQueue.size() > 0){ try { BoatPositionPacket positionPacket = movementQueue.take(); @@ -244,6 +253,26 @@ public class CanvasController { group.getChildren().addAll(boatGroups); } + private void initializeMarks() { + Map allMarks = StreamParser.getXmlObject().getRaceXML().getCompoundMarks(); + + for (Mark mark : allMarks.values()) { + if (mark.getMarkType() == MarkType.SINGLE_MARK) { + SingleMark sMark = (SingleMark) mark; + + MarkGroup markGroup = new MarkGroup(mark, findScaledXY(sMark)); + markGroups.add(markGroup); + } else { + GateMark gMark = (GateMark) mark; + + MarkGroup markGroup = new MarkGroup(mark, findScaledXY(gMark.getSingleMark1()), + findScaledXY(gMark.getSingleMark2())); //should be 2 objects in the list. + markGroups.add(markGroup); + } + } + group.getChildren().addAll(markGroups); + } + class ResizableCanvas extends Canvas { ResizableCanvas() { diff --git a/src/main/java/seng302/models/mark/Mark.java b/src/main/java/seng302/models/mark/Mark.java index ce5a6f4a..1ca1f608 100644 --- a/src/main/java/seng302/models/mark/Mark.java +++ b/src/main/java/seng302/models/mark/Mark.java @@ -10,7 +10,7 @@ public abstract class Mark { private MarkType markType; private double latitude; private double longitude; - private int id; + private long id; /** * Create a mark instance by passing its name and type @@ -125,7 +125,7 @@ public abstract class Mark { return longitude; } - public int getId() { + public long getId() { return id; } diff --git a/src/main/java/seng302/models/mark/MarkGroup.java b/src/main/java/seng302/models/mark/MarkGroup.java index 0e886abc..bdd1491d 100644 --- a/src/main/java/seng302/models/mark/MarkGroup.java +++ b/src/main/java/seng302/models/mark/MarkGroup.java @@ -1,14 +1,12 @@ package seng302.models.mark; +import java.util.ArrayList; +import java.util.List; import javafx.geometry.Point2D; import javafx.scene.Group; import javafx.scene.paint.Color; import javafx.scene.shape.Circle; import javafx.scene.shape.Line; -import javafx.scene.transform.Rotate; - -import java.util.ArrayList; -import java.util.List; /** * Created by CJIRWIN on 26/04/2017. @@ -72,7 +70,7 @@ public class MarkGroup extends Group { } } - public void moveMarkTo (double x, double y, int raceId) + public void moveMarkTo (double x, double y, long raceId) { if (mainMark.getMarkType() == MarkType.SINGLE_MARK) { Circle markCircle = (Circle) super.getChildren().get(0); @@ -104,8 +102,8 @@ public class MarkGroup extends Group { return false; } - public int[] getRaceIds () { - int[] idArray = new int[marks.size()]; + public long[] getRaceIds () { + long[] idArray = new long[marks.size()]; int i = 0; for (Mark mark : marks) idArray[i++] = mark.getId(); diff --git a/src/main/java/seng302/models/stream/StreamParser.java b/src/main/java/seng302/models/stream/StreamParser.java index f7093306..0b685da2 100644 --- a/src/main/java/seng302/models/stream/StreamParser.java +++ b/src/main/java/seng302/models/stream/StreamParser.java @@ -1,6 +1,23 @@ package seng302.models.stream; +import java.io.IOException; +import java.io.StringReader; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.Date; +import java.util.Map; +import java.util.TimeZone; +import java.util.TreeMap; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentSkipListMap; +import java.util.concurrent.PriorityBlockingQueue; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; import org.w3c.dom.Document; import org.xml.sax.InputSource; import org.xml.sax.SAXException; @@ -8,19 +25,6 @@ import seng302.models.Yacht; import seng302.models.stream.packets.BoatPositionPacket; import seng302.models.stream.packets.StreamPacket; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import java.io.IOException; -import java.io.StringReader; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentSkipListMap; -import java.util.concurrent.PriorityBlockingQueue; -import seng302.models.stream.XMLParser; - /** * The purpose of this class is to take in the stream of divided packets so they can be read * and parsed in by turning the byte arrays into useful data. There are two public static hashmaps @@ -29,6 +33,7 @@ import seng302.models.stream.XMLParser; */ public class StreamParser extends Thread{ + public static ConcurrentHashMap> markPositions = new ConcurrentHashMap<>(); public static ConcurrentHashMap> boatPositions = new ConcurrentHashMap<>(); private String threadName; private Thread t; @@ -400,6 +405,20 @@ public class StreamParser extends Thread{ })); } boatPositions.get(boatId).put(boatPacket); + } else if (deviceType == 3){ + BoatPositionPacket markPacket = new BoatPositionPacket(boatId, timeValid, lat, lon, heading, groundSpeed); + + //add a new priority que to the boatPositions HashMap + if (!markPositions.containsKey(boatId)) { + markPositions.put(boatId, + new PriorityBlockingQueue<>(256, new Comparator() { + @Override + public int compare(BoatPositionPacket p1, BoatPositionPacket p2) { + return (int) (p1.getTimeValid() - p2.getTimeValid()); + } + })); + } + markPositions.get(boatId).put(markPacket); } } diff --git a/src/main/java/seng302/models/stream/XMLParser.java b/src/main/java/seng302/models/stream/XMLParser.java index 43595cea..53bb0889 100644 --- a/src/main/java/seng302/models/stream/XMLParser.java +++ b/src/main/java/seng302/models/stream/XMLParser.java @@ -1,6 +1,9 @@ package seng302.models.stream; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; @@ -9,10 +12,6 @@ import seng302.models.Yacht; import seng302.models.mark.GateMark; import seng302.models.mark.Mark; import seng302.models.mark.MarkType; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; import seng302.models.mark.SingleMark; /** @@ -349,7 +348,6 @@ public class XMLParser { } } - System.out.println(marksList.size()); if (marksList.size() == 1) { return marksList.get(0); } else if (marksList.size() == 2) { From b692ddcbe609598a8993fee15687452d06f936b7 Mon Sep 17 00:00:00 2001 From: Alistair McIntyre Date: Thu, 18 May 2017 18:39:23 +1200 Subject: [PATCH 19/32] Marks and gates correctly displaying from XML messages and mark(boat) position packets. Will need a little polishing but marks and gates are moving around. #story[923] #pair[ajm412, ptg19] --- .../seng302/controllers/CanvasController.java | 7 +- .../java/seng302/models/mark/MarkGroup.java | 92 +++++++++++-------- 2 files changed, 57 insertions(+), 42 deletions(-) diff --git a/src/main/java/seng302/controllers/CanvasController.java b/src/main/java/seng302/controllers/CanvasController.java index c7fbcb6e..40642f41 100644 --- a/src/main/java/seng302/controllers/CanvasController.java +++ b/src/main/java/seng302/controllers/CanvasController.java @@ -223,7 +223,7 @@ public class CanvasController { } } - void UpdateMarkGroup (long raceId, MarkGroup markGroup) { + private void UpdateMarkGroup (long raceId, MarkGroup markGroup) { PriorityBlockingQueue movementQueue = StreamParser.markPositions.get(raceId); if (movementQueue.size() > 0){ try { @@ -260,13 +260,12 @@ public class CanvasController { if (mark.getMarkType() == MarkType.SINGLE_MARK) { SingleMark sMark = (SingleMark) mark; - MarkGroup markGroup = new MarkGroup(mark, findScaledXY(sMark)); + MarkGroup markGroup = new MarkGroup(sMark, findScaledXY(sMark)); markGroups.add(markGroup); } else { GateMark gMark = (GateMark) mark; - MarkGroup markGroup = new MarkGroup(mark, findScaledXY(gMark.getSingleMark1()), - findScaledXY(gMark.getSingleMark2())); //should be 2 objects in the list. + MarkGroup markGroup = new MarkGroup(gMark, findScaledXY(gMark.getSingleMark1()), findScaledXY(gMark.getSingleMark2())); //should be 2 objects in the list. markGroups.add(markGroup); } } diff --git a/src/main/java/seng302/models/mark/MarkGroup.java b/src/main/java/seng302/models/mark/MarkGroup.java index bdd1491d..ecb0cdc7 100644 --- a/src/main/java/seng302/models/mark/MarkGroup.java +++ b/src/main/java/seng302/models/mark/MarkGroup.java @@ -21,7 +21,12 @@ public class MarkGroup extends Group { private List marks = new ArrayList<>(); private Mark mainMark; - public MarkGroup (Mark mark, Point2D... points) { + /** + * Constructor for singleMark groups + * @param mark + * @param points + */ + public MarkGroup (SingleMark mark, Point2D points) { marks.add(mark); mainMark = mark; Color color = Color.BLACK; @@ -31,43 +36,54 @@ public class MarkGroup extends Group { color = Color.RED; } Circle markCircle; - if (mark.getMarkType() == MarkType.SINGLE_MARK) { - markCircle = new Circle( - points[0].getX(), - points[0].getY(), - MARK_RADIUS, - color - ); - super.getChildren().add(markCircle); - } else { - markCircle = new Circle( - points[0].getX(), - points[0].getY(), - MARK_RADIUS, - color - ); - super.getChildren().add(markCircle); + markCircle = new Circle( + points.getX(), + points.getY(), + MARK_RADIUS, + color + ); + super.getChildren().add(markCircle); + } - markCircle = new Circle( - points[1].getX(), - points[1].getY(), - MARK_RADIUS, - color - ); - super.getChildren().add(markCircle); - Line line = new Line( - points[0].getX(), - points[0].getY(), - points[1].getX(), - points[1].getY() - ); - line.setStrokeWidth(LINE_THICKNESS); - line.setStroke(color); - if (mark.getMarkType() == MarkType.OPEN_GATE) { - line.getStrokeDashArray().addAll(DASHED_GAP_LEN, DASHED_LINE_LEN); - } - super.getChildren().add(line); + public MarkGroup(GateMark mark, Point2D points1, Point2D points2) { + marks.add(mark.getSingleMark1()); + marks.add(mark.getSingleMark2()); + mainMark = mark; + Color color = Color.BLACK; + if (mark.getName().equals("Start")){ + color = Color.GREEN; + } else if (mark.getName().equals("Finish")){ + color = Color.RED; } + Circle markCircle; + markCircle = new Circle( + points1.getX(), + points1.getY(), + MARK_RADIUS, + color + ); + super.getChildren().add(markCircle); + + markCircle = new Circle( + points2.getX(), + points2.getY(), + MARK_RADIUS, + color + ); + super.getChildren().add(markCircle); + Line line = new Line( + points1.getX(), + points1.getY(), + points2.getX(), + points2.getY() + ); + line.setStrokeWidth(LINE_THICKNESS); + line.setStroke(color); + if (mark.getMarkType() == MarkType.OPEN_GATE) { + line.getStrokeDashArray().addAll(DASHED_GAP_LEN, DASHED_LINE_LEN); + } + super.getChildren().add(line); + } public void moveMarkTo (double x, double y, long raceId) @@ -80,12 +96,12 @@ public class MarkGroup extends Group { Circle markCircle1 = (Circle) super.getChildren().get(0); Circle markCircle2 = (Circle) super.getChildren().get(1); Line connectingLine = (Line) super.getChildren().get(2); - if (marks.get(1).getId() == raceId) { + if (marks.get(0).getId() == raceId) { markCircle1.setCenterX(x); markCircle1.setCenterY(y); connectingLine.setStartX(markCircle1.getCenterX()); connectingLine.setStartY(markCircle1.getCenterY()); - } else if (marks.get(2).getId() == raceId) { + } else if (marks.get(1).getId() == raceId) { markCircle2.setCenterX(x); markCircle2.setCenterY(y); connectingLine.setEndX(markCircle2.getCenterX()); From aaf2e6a3f0587e94c8a428112cf01984d1edfc85 Mon Sep 17 00:00:00 2001 From: Michael Rausch Date: Fri, 19 May 2017 16:57:29 +1200 Subject: [PATCH 20/32] Added boat wakes back to the visualiser #story[923] --- src/main/java/seng302/App.java | 3 + .../controllers/RaceViewController.java | 2 +- .../controllers/StartScreenController.java | 1 + src/main/java/seng302/models/BoatGroup.java | 48 ++++++++ src/main/java/seng302/models/Wake.java | 103 ++++++++++-------- 5 files changed, 108 insertions(+), 49 deletions(-) diff --git a/src/main/java/seng302/App.java b/src/main/java/seng302/App.java index ac264db6..3e464525 100644 --- a/src/main/java/seng302/App.java +++ b/src/main/java/seng302/App.java @@ -17,6 +17,9 @@ public class App extends Application { primaryStage.setTitle("RaceVision"); primaryStage.setScene(new Scene(root)); primaryStage.setMaximized(true); + primaryStage.setFullScreenExitHint(""); + primaryStage.setFullScreen(true); + primaryStage.show(); primaryStage.setOnCloseRequest(e -> { diff --git a/src/main/java/seng302/controllers/RaceViewController.java b/src/main/java/seng302/controllers/RaceViewController.java index 8492015b..43c04a9b 100644 --- a/src/main/java/seng302/controllers/RaceViewController.java +++ b/src/main/java/seng302/controllers/RaceViewController.java @@ -105,7 +105,7 @@ public class RaceViewController extends Thread implements ImportantAnnotationDel // Load FXML and set CSS fxmlLoader .setLocation(getClass().getResource("/views/importantAnnotationSelectView.fxml")); - Scene scene = new Scene(fxmlLoader.load(), 469, 248); + Scene scene = new Scene(fxmlLoader.load(), 469, 298); scene.getStylesheets().add(getClass().getResource("/css/master.css").toString()); stage.initStyle(StageStyle.UNDECORATED); diff --git a/src/main/java/seng302/controllers/StartScreenController.java b/src/main/java/seng302/controllers/StartScreenController.java index 94851d05..bf1456a8 100644 --- a/src/main/java/seng302/controllers/StartScreenController.java +++ b/src/main/java/seng302/controllers/StartScreenController.java @@ -132,6 +132,7 @@ public class StartScreenController implements Initializable { } public void switchToRaceView() { + StreamParser.boatPositions.clear(); switchedToRaceView = true; setContentPane("/views/RaceView.fxml"); } diff --git a/src/main/java/seng302/models/BoatGroup.java b/src/main/java/seng302/models/BoatGroup.java index 28e9561f..0f606f4d 100644 --- a/src/main/java/seng302/models/BoatGroup.java +++ b/src/main/java/seng302/models/BoatGroup.java @@ -39,6 +39,7 @@ public class BoatGroup extends Group{ private double xIncrement; private double yIncrement; private long lastTimeValid = 0; + private Double lastRotation = 0.0; private long framesToMove; //Graphical objects private Yacht boat; @@ -159,6 +160,9 @@ public class BoatGroup extends Group{ estTimeToNextMarkObject.setLayoutY(estTimeToNextMarkObject.getLayoutY() + dy); legTimeObject.setLayoutX(legTimeObject.getLayoutX() + dx); legTimeObject.setLayoutY(legTimeObject.getLayoutY() + dy); + //////// + wake.setLayoutX(wake.getLayoutX() + dx); + wake.setLayoutY(wake.getLayoutY() + dy); } @@ -179,6 +183,11 @@ public class BoatGroup extends Group{ estTimeToNextMarkObject.setLayoutY(y); legTimeObject.setLayoutX(x); legTimeObject.setLayoutY(y); + ///////// + wake.setLayoutX(x); + wake.setLayoutY(y); + wake.rotate(rotation); + } public void rotateTo (double rotation) { @@ -191,8 +200,35 @@ public class BoatGroup extends Group{ if (framesToMove <= 0){ isStopped = true; } + //////////// + wake.updatePosition(1000/60); } + /////////// + /** + * Calculates the rotational velocity required to reach the rotationalGoal from the currentRotation. + */ + protected Double calculateRotationalVelocity (Double rotationalGoal) { + Double rotationalVelocity = 0.0; + + if (Math.abs(rotationalGoal - lastRotation) > 180) { + if (rotationalGoal - lastRotation >= 0.0) { + rotationalVelocity = ((rotationalGoal - lastRotation) - 360) / 200; + } else { + rotationalVelocity = (360 + (rotationalGoal - lastRotation)) / 200; + } + } else { + rotationalVelocity = (rotationalGoal - lastRotation) / 200; + } + + //Sometimes the rotation is too large to be realistic. In that case just do it instantly. + if (Math.abs(rotationalVelocity) > 1) { + rotationalVelocity = 0.0; + } + + return rotationalVelocity; + } + /** * Sets the destination of the boat and the headng it should have once it reaches * @param newXValue The X co-ordinate the boat needs to move to. @@ -208,13 +244,25 @@ public class BoatGroup extends Group{ framesToMove = Math.round((frameRate/(1000.0f/(timeValid-lastTimeValid)))); double dx = newXValue - boatPoly.getLayoutX(); double dy = newYValue - boatPoly.getLayoutY(); + xIncrement = dx/framesToMove; yIncrement = dy/framesToMove; + + Double rotationalVelocity = calculateRotationalVelocity(rotation); + + if (Math.abs(rotationalVelocity) > 0.075) { + rotationalVelocity = 0.0; + wake.rotate(rotation); + } + rotateTo(rotation); + wake.setRotationalVelocity(rotationalVelocity, groundSpeed); velocityObject.setText(String.format("%.2f m/s", groundSpeed)); lastTimeValid = timeValid; isStopped = false; + + lastRotation = rotation; } diff --git a/src/main/java/seng302/models/Wake.java b/src/main/java/seng302/models/Wake.java index 55d4381c..886dfba8 100644 --- a/src/main/java/seng302/models/Wake.java +++ b/src/main/java/seng302/models/Wake.java @@ -1,30 +1,34 @@ package seng302.models; +import javafx.scene.CacheHint; import javafx.scene.Group; import javafx.scene.paint.Color; import javafx.scene.shape.Arc; import javafx.scene.shape.ArcType; +import javafx.scene.shape.StrokeLineCap; import javafx.scene.transform.Rotate; /** - * By default wake is a group containing 5 arcs. Each arc starts from the same point. Each arc is larger and more - * transparent than the last. On calling updatePositions() arcs rotate at velocities given by setRotationalVelocity(). - * The larger and more transparent an arc is the longer the delay before it rotates at the latest velocity. It is - * assumed that rotationalVelocities() are set regularly as wakes do not stop rotating and an array of velocities needs - * to be populated for the class to work as expected. + * A group containing objects used to represent wakes onscreen. Contains functionality for their animation. */ class Wake extends Group { - private int numWakes = 5; - private double[] velocities = new double[13]; + //The number of wakes + private int numWakes = 8; + //The total possible difference between the first wake and the last. Increasing/Decreasing this will make wakes fan out more/less. + private final double MAX_DIFF = 75; + //Increasing/decreasing this will alter the speed that wakes converge when the heading stop changing. Anything over about 1500 may cause oscillation. + private final int UNIFICATION_SPEED = 750; + + private Arc[] arcs = new Arc[numWakes]; + private double[] rotationalVelocities = new double[numWakes]; private double[] rotations = new double[numWakes]; - private int[] velocityIndices = new int[numWakes]; - private double sum = 0; - private static double max; + private double baseRad; /** * Create a wake at the given location. + * * @param startingX x location where the tip of wake arcs will be. * @param startingY y location where the tip of wake arcs will be. */ @@ -34,74 +38,77 @@ class Wake extends Group { Arc arc; for (int i = 0; i < numWakes; i++) { //Default triangle is -110 deg out of phase with a default wake and has angle of 40 deg. - arc = new Arc(0,0,0,0,-110,40); - //Opacity increases from 0.5 -> 0 evenly over the 5 wake arcs. - arc.setFill(new Color(0.18, 0.7, 1.0, 1.0 + -0.175 * i)); - arc.setType(ArcType.ROUND); + arc = new Arc(0, 0, 0, 0, -110, 40); + arc.setCache(true); + arc.setCacheHint(CacheHint.SPEED); + arc.setType(ArcType.OPEN); + arc.setStroke(new Color(0.18, 0.7, 1.0, 1.0 + (-0.99 / numWakes * i))); + arc.setStrokeWidth(3.0); + arc.setStrokeLineCap(StrokeLineCap.ROUND); + arc.setFill(new Color(0.0, 0.0, 0.0, 0.0)); + baseRad = (20 / numWakes); arcs[i] = arc; } super.getChildren().addAll(arcs); } /** - * Sets the rotationalVelocity of each arc. Each arc is 3 velocities behind the next smallest arc. The smallest uses - * the latest given velocity. + * Sets the rotationalVelocity of each arc. + * * @param rotationalVelocity The rotationalVelocity the wake should move at. - * @param rotationGoal Where the wake will rotate to if the wake is calculated to be on a straight section. This is - * used to prevent desynchronisation with the Boat polygon. - * @param velocity The real world velocity of the boat in m/s. + * @param velocity The real world velocity of the boat in m/s. */ - void setRotationalVelocity (double rotationalVelocity, double rotationGoal, double velocity) { - sum -= Math.abs(velocities[(velocityIndices[0] + 10) % 13]); - sum += Math.abs(rotationalVelocity); - max = Math.max(max, rotationalVelocity); - if (sum < (max / 3)) - rotate (rotationGoal); //In relatively straight segments the wake snaps to match the boats current position. - //This stops the wake from eventually becoming out of sync with the boat. - //This accounts for rogue rotations that are greater than what would be realistic. Value is kinda rough. - //Basically just for our internal mock. - if (Math.abs(rotationalVelocity) > 0.05) { - rotationalVelocity = 0; - rotate(rotationGoal); - } - //Update the index of the array of recent velocities that each wake uses. Each wake is 3 velocities behind the - //next smallest wake. - velocityIndices[0] = (13 + (velocityIndices[0] - 1) % 13) % 13; - velocities[velocityIndices[0]] = rotationalVelocity; - for (int i = 1; i < numWakes; i++) - velocityIndices[i] = (velocityIndices[0] + 3 * i) % 13; + void setRotationalVelocity(double rotationalVelocity, double velocity) { + rotationalVelocities[0] = rotationalVelocity; + for (int i = 1; i < numWakes; i++) { + double wakeSeparationRad = Math.toRadians(rotations[i - 1] - rotations[i]); + double shortestDistance = Math.atan2( + Math.sin(wakeSeparationRad), + Math.cos(wakeSeparationRad) + ); + double distDeg = Math.toDegrees(shortestDistance); - //Scale wakes based on velocity. - double baseRad = 20; - double rad; - for (Arc arc :arcs) { - rad = baseRad + velocity; + if (rotationalVelocities[i - 1] < 0.01 && rotationalVelocities[i - 1] > -0.01) { + rotationalVelocities[i] = distDeg / UNIFICATION_SPEED * Math.log(Math.abs(distDeg) + 1) / Math.log(MAX_DIFF / numWakes); + + } else { + if (distDeg < (MAX_DIFF / numWakes)) + rotationalVelocities[i] = rotationalVelocities[i - 1] * Math.log(Math.abs(distDeg) + 1) / Math.log(MAX_DIFF / numWakes); + else + rotationalVelocities[i] = rotationalVelocities[i - 1]; + } + } + + double rad = baseRad + velocity; + for (Arc arc : arcs) { arc.setRadiusX(rad); arc.setRadiusY(rad); - baseRad += 5 + (velocity / 2); + rad += (20 / numWakes) + (velocity / 2); } } /** * Arcs rotate based on the distance they would have travelled over the supplied time interval. + * * @param timeInterval the time interval, in microseconds, that the wake should move. */ - void updatePosition (long timeInterval) { + void updatePosition(long timeInterval) { for (int i = 0; i < numWakes; i++) { - rotations[i] = rotations[i] + velocities[velocityIndices[i]] * timeInterval; + rotations[i] = rotations[i] + rotationalVelocities[i] * timeInterval; arcs[i].getTransforms().setAll(new Rotate(rotations[i])); } } /** * Rotate all wakes to the given rotation. + * * @param rotation the from north angle in degrees to rotate to. */ - void rotate (double rotation) { + void rotate(double rotation) { for (int i = 0; i < arcs.length; i++) { rotations[i] = rotation; + rotationalVelocities[i] = 0; arcs[i].getTransforms().setAll(new Rotate(rotation)); } } - } From 937b309b07273e6a28c971712349838292d5199c Mon Sep 17 00:00:00 2001 From: Michael Rausch Date: Fri, 19 May 2017 20:55:02 +1200 Subject: [PATCH 21/32] Added boat trails to the boat group, fixed annotations - Set colours for the annotations - Added boat trails back into the boat group - Re-added time until next mark and time since last mark rounding #story[923] --- src/main/java/seng302/App.java | 2 - .../seng302/controllers/CanvasController.java | 4 +- src/main/java/seng302/models/BoatGroup.java | 153 +++++++++++++----- src/main/java/seng302/models/Colors.java | 2 +- src/main/java/seng302/models/Yacht.java | 2 +- 5 files changed, 121 insertions(+), 42 deletions(-) diff --git a/src/main/java/seng302/App.java b/src/main/java/seng302/App.java index 3e464525..ef5bc582 100644 --- a/src/main/java/seng302/App.java +++ b/src/main/java/seng302/App.java @@ -17,8 +17,6 @@ public class App extends Application { primaryStage.setTitle("RaceVision"); primaryStage.setScene(new Scene(root)); primaryStage.setMaximized(true); - primaryStage.setFullScreenExitHint(""); - primaryStage.setFullScreen(true); primaryStage.show(); diff --git a/src/main/java/seng302/controllers/CanvasController.java b/src/main/java/seng302/controllers/CanvasController.java index ff7a294f..bebd1861 100644 --- a/src/main/java/seng302/controllers/CanvasController.java +++ b/src/main/java/seng302/controllers/CanvasController.java @@ -181,7 +181,7 @@ public class CanvasController { for (MarkGroup markGroup : markGroups) { for (int id : markGroup.getRaceIds()) { if (StreamParser.boatPositions.containsKey(id)) { - UpdateMarkGroup(id, markGroup); + updateMarkGroup(id, markGroup); } } } @@ -214,7 +214,7 @@ public class CanvasController { } } - void UpdateMarkGroup (int raceId, MarkGroup markGroup) { + void updateMarkGroup (int raceId, MarkGroup markGroup) { PriorityBlockingQueue movementQueue = StreamParser.boatPositions.get(raceId); if (movementQueue.size() > 0){ try { diff --git a/src/main/java/seng302/models/BoatGroup.java b/src/main/java/seng302/models/BoatGroup.java index 0f606f4d..6a6c0370 100644 --- a/src/main/java/seng302/models/BoatGroup.java +++ b/src/main/java/seng302/models/BoatGroup.java @@ -1,11 +1,14 @@ package seng302.models; import javafx.event.EventHandler; +import javafx.geometry.Point2D; import javafx.scene.CacheHint; import javafx.scene.Group; import javafx.scene.input.MouseDragEvent; import javafx.scene.input.MouseEvent; import javafx.scene.paint.Color; +import javafx.scene.paint.Paint; +import javafx.scene.shape.Line; import javafx.scene.shape.Polygon; import javafx.scene.text.Text; import javafx.scene.transform.Rotate; @@ -50,6 +53,10 @@ public class BoatGroup extends Group{ private Text estTimeToNextMarkObject; private Text legTimeObject; private Wake wake; + private Double distanceTravelled = 0.0; + private Point2D lastPoint; + private boolean destinationSet; + private Color textColor = Color.RED; private Boolean isSelected = true; //All boats are initalised as selected @@ -62,6 +69,7 @@ public class BoatGroup extends Group{ public BoatGroup (Yacht boat, Color color){ this.boat = boat; initChildren(color); + this.textColor = color; } /** @@ -77,12 +85,31 @@ public class BoatGroup extends Group{ initChildren(color, points); } + /** + * Return a text object with caching and a color applied + * @param defaultText The default text to display + * @param fill The text fill color + * @return The text object + */ + private Text getTextObject(String defaultText, Color fill){ + Text text = new Text(defaultText); + + text.setFill(fill); + text.setCacheHint(CacheHint.SPEED); + text.setCache(true); + + return text; + } + /** * Creates the javafx objects that will be the in the group by default. * @param color The colour of the boat polygon and the trailing line. * @param points An array of co-ordinates x1,y1,x2,y2,x3,y3... that will make up the boat polygon. */ private void initChildren (Color color, double... points) { + textColor = color; + destinationSet = false; + boatPoly = new Polygon(points); boatPoly.setFill(color); boatPoly.setOnMouseEntered(event -> boatPoly.setFill(Color.FLORALWHITE)); @@ -91,24 +118,8 @@ public class BoatGroup extends Group{ boatPoly.setCache(true); boatPoly.setCacheHint(CacheHint.SPEED); - - teamNameObject = new Text(boat.getShortName()); - teamNameObject.setCache(true); - teamNameObject.setCacheHint(CacheHint.SPEED); - velocityObject = new Text(String.valueOf(boat.getVelocity())); - DateFormat format = new SimpleDateFormat("mm:ss"); - String timeToNextMark = format - .format(boat.getEstimateTimeAtNextMark() - StreamParser.getCurrentTimeLong()); - estTimeToNextMarkObject = new Text("Next mark: " + timeToNextMark); - if (boat.getMarkRoundingTime() != null) { - String elapsedTime = format - .format(StreamParser.getCurrentTimeLong() - boat.getMarkRoundingTime()); - legTimeObject = new Text("Last mark: " + elapsedTime); - } else { - legTimeObject = new Text("Last mark: -"); - } - velocityObject.setCache(true); - velocityObject.setCacheHint(CacheHint.SPEED); + teamNameObject = getTextObject(boat.getShortName(), textColor); + velocityObject = getTextObject(boat.getVelocity().toString(), textColor); teamNameObject.setX(TEAMNAME_X_OFFSET); teamNameObject.setY(TEAMNAME_Y_OFFSET); @@ -118,14 +129,22 @@ public class BoatGroup extends Group{ velocityObject.setY(VELOCITY_Y_OFFSET); velocityObject.relocate(velocityObject.getX(), velocityObject.getY()); - estTimeToNextMarkObject.setX(ESTTIMETONEXTMARK_X_OFFSET); - estTimeToNextMarkObject.setY(ESTTIMETONEXTMARK_Y_OFFSET); - estTimeToNextMarkObject - .relocate(estTimeToNextMarkObject.getX(), estTimeToNextMarkObject.getY()); + updateLastMarkRoundingTime(); + updateTimeTillNextMark(); - legTimeObject.setX(LEGTIME_X_OFFSET); - legTimeObject.setY(LEGTIME_Y_OFFSET); - legTimeObject.relocate(legTimeObject.getX(), legTimeObject.getY()); + if (estTimeToNextMarkObject != null){ + estTimeToNextMarkObject.setX(ESTTIMETONEXTMARK_X_OFFSET); + estTimeToNextMarkObject.setY(ESTTIMETONEXTMARK_Y_OFFSET); + estTimeToNextMarkObject + .relocate(estTimeToNextMarkObject.getX(), estTimeToNextMarkObject.getY()); + } + + if (legTimeObject != null){ + legTimeObject.setX(LEGTIME_X_OFFSET); + legTimeObject.setY(LEGTIME_Y_OFFSET); + legTimeObject.relocate(legTimeObject.getX(), legTimeObject.getY()); + + } wake = new Wake(0, -BOAT_HEIGHT); super.getChildren() @@ -149,7 +168,7 @@ public class BoatGroup extends Group{ * @param dx The amount to move the X coordinate by * @param dy The amount to move the Y coordinate by */ - public void moveGroupBy(double dx, double dy) { + private void moveGroupBy(double dx, double dy) { boatPoly.setLayoutX(boatPoly.getLayoutX() + dx); boatPoly.setLayoutY(boatPoly.getLayoutY() + dy); teamNameObject.setLayoutX(teamNameObject.getLayoutX() + dx); @@ -160,7 +179,6 @@ public class BoatGroup extends Group{ estTimeToNextMarkObject.setLayoutY(estTimeToNextMarkObject.getLayoutY() + dy); legTimeObject.setLayoutX(legTimeObject.getLayoutX() + dx); legTimeObject.setLayoutY(legTimeObject.getLayoutY() + dy); - //////// wake.setLayoutX(wake.getLayoutX() + dx); wake.setLayoutY(wake.getLayoutY() + dy); } @@ -171,7 +189,7 @@ public class BoatGroup extends Group{ * @param x The X coordinate to move the boat to * @param y The Y coordinate to move the boat to */ - public void moveTo (double x, double y, double rotation) { + private void moveTo(double x, double y, double rotation) { rotateTo(rotation); boatPoly.setLayoutX(x); boatPoly.setLayoutY(y); @@ -183,28 +201,86 @@ public class BoatGroup extends Group{ estTimeToNextMarkObject.setLayoutY(y); legTimeObject.setLayoutX(x); legTimeObject.setLayoutY(y); - ///////// - wake.setLayoutX(x); - wake.setLayoutY(y); - wake.rotate(rotation); - + wake.setLayoutX(x); + wake.setLayoutY(y); + wake.rotate(rotation); } - public void rotateTo (double rotation) { + private void rotateTo(double rotation) { boatPoly.getTransforms().setAll(new Rotate(rotation)); } + /** + * Updates the time until next mark label, will create a label if one doesn't exist + */ + private void updateTimeTillNextMark(){ + if (estTimeToNextMarkObject == null){ + estTimeToNextMarkObject = getTextObject("", textColor); + } + + DateFormat format = new SimpleDateFormat("mm:ss"); + String timeToNextMark = format + .format(boat.getEstimateTimeAtNextMark() - StreamParser.getCurrentTimeLong()); + estTimeToNextMarkObject.setText("Next mark: " + timeToNextMark); + } + + /** + * Updates the time since last mark rounding, will create a label if one doesn't exist + */ + private void updateLastMarkRoundingTime(){ + if (legTimeObject == null){ + legTimeObject = getTextObject("", textColor); + } + + if (boat.getMarkRoundingTime() != null){ + DateFormat format = new SimpleDateFormat("mm:ss"); + String elapsedTime = format + .format(StreamParser.getCurrentTimeLong() - boat.getMarkRoundingTime()); + legTimeObject.setText("Last mark: " + elapsedTime); + } + else{ + legTimeObject.setText("Last mark: -"); + + } + } + public void move() { + double dx = xIncrement * framesToMove; + double dy = yIncrement * framesToMove; + + distanceTravelled += Math.abs(dx) + Math.abs(dy); moveGroupBy(xIncrement, yIncrement); framesToMove = framesToMove - 1; + if (framesToMove <= 0){ isStopped = true; } - //////////// + + if (distanceTravelled > 70){ + distanceTravelled = 0d; + + if (lastPoint != null){ + Line l = new Line( + lastPoint.getX(), + lastPoint.getY(), + boatPoly.getLayoutX(), + boatPoly.getLayoutY() + ); + l.getStrokeDashArray().setAll(3d, 7d); + l.setStroke(boat.getColour()); + l.setCache(true); + l.setCacheHint(CacheHint.SPEED); + lineGroup.getChildren().add(l); + } + + if (destinationSet){ + lastPoint = new Point2D(boatPoly.getLayoutX(), boatPoly.getLayoutY()); + } + } + wake.updatePosition(1000/60); } - /////////// /** * Calculates the rotational velocity required to reach the rotationalGoal from the currentRotation. */ @@ -248,8 +324,13 @@ public class BoatGroup extends Group{ xIncrement = dx/framesToMove; yIncrement = dy/framesToMove; + destinationSet = true; + Double rotationalVelocity = calculateRotationalVelocity(rotation); + updateTimeTillNextMark(); + updateLastMarkRoundingTime(); + if (Math.abs(rotationalVelocity) > 0.075) { rotationalVelocity = 0.0; wake.rotate(rotation); diff --git a/src/main/java/seng302/models/Colors.java b/src/main/java/seng302/models/Colors.java index 23ef8f4e..8d1b9c25 100644 --- a/src/main/java/seng302/models/Colors.java +++ b/src/main/java/seng302/models/Colors.java @@ -6,7 +6,7 @@ import javafx.scene.paint.Color; * Created by ryan_ on 16/03/2017. */ public enum Colors { - RED, ORANGE, YELLOW, GREEN, BLUE, PURPLE; + RED, PERU, SEAGREEN, GREEN, BLUE, PURPLE; static Integer index = 0; diff --git a/src/main/java/seng302/models/Yacht.java b/src/main/java/seng302/models/Yacht.java index 23ba616a..8ae5d76c 100644 --- a/src/main/java/seng302/models/Yacht.java +++ b/src/main/java/seng302/models/Yacht.java @@ -151,7 +151,7 @@ public class Yacht { this.colour = colour; } - public double getVelocity() { + public Double getVelocity() { return velocity; } From 5adb7c3762156deaddb8e99cd5bfa4999e228929 Mon Sep 17 00:00:00 2001 From: Michael Rausch Date: Fri, 19 May 2017 20:57:40 +1200 Subject: [PATCH 22/32] Fixed failing ColorsTest #story[923] --- src/test/java/seng302/ColorsTest.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/test/java/seng302/ColorsTest.java b/src/test/java/seng302/ColorsTest.java index 6fc07b41..03bc9ad2 100644 --- a/src/test/java/seng302/ColorsTest.java +++ b/src/test/java/seng302/ColorsTest.java @@ -8,14 +8,11 @@ import seng302.models.Colors; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; -/** - * Created by ryan_ on 16/03/2017. - */ public class ColorsTest { @Test public void testNextColor() { - Color expectedColors[] = {Color.RED, Color.ORANGE, Color.YELLOW, Color.GREEN, Color.BLUE, Color.PURPLE}; + Color expectedColors[] = {Color.RED, Color.PERU, Color.SEAGREEN, Color.GREEN, Color.BLUE, Color.PURPLE}; for (int i = 0; i<6; i++) { Assert.assertEquals(expectedColors[i], Colors.getColor()); From 059c0de1fad98ae93e3afaeef8ffa12231b1dbec Mon Sep 17 00:00:00 2001 From: Kusal Ekanayake Date: Sun, 21 May 2017 15:58:17 +1200 Subject: [PATCH 23/32] Quickfix for null pointer in boatObject #pair[ptg19,kre39] --- src/main/java/seng302/models/BoatGroup.java | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/main/java/seng302/models/BoatGroup.java b/src/main/java/seng302/models/BoatGroup.java index 767ca893..f6e4a16b 100644 --- a/src/main/java/seng302/models/BoatGroup.java +++ b/src/main/java/seng302/models/BoatGroup.java @@ -109,9 +109,13 @@ public class BoatGroup extends RaceObject { teamNameObject.setCacheHint(CacheHint.SPEED); velocityObject = new Text(String.valueOf(boat.getVelocity())); DateFormat format = new SimpleDateFormat("mm:ss"); - String timeToNextMark = format + // TODO: 21/05/17 make a nice way of checking for this to be null + estTimeToNextMarkObject = new Text("Next mark: null"); + if (boat.getEstimateTimeAtNextMark() != null) { + String timeToNextMark = format .format(boat.getEstimateTimeAtNextMark() - StreamParser.getCurrentTimeLong()); - estTimeToNextMarkObject = new Text("Next mark: " + timeToNextMark); + estTimeToNextMarkObject = new Text("Next mark: " + timeToNextMark); + } if (boat.getMarkRoundingTime() != null) { String elapsedTime = format .format(StreamParser.getCurrentTimeLong() - boat.getMarkRoundingTime()); @@ -280,9 +284,14 @@ public class BoatGroup extends RaceObject { velocityObject.setText(String.format("%.2f m/s", boat.getVelocity())); DateFormat format = new SimpleDateFormat("mm:ss"); // estimate time to next mark - String timeToNextMark = format - .format(boat.getEstimateTimeAtNextMark() - StreamParser.getCurrentTimeLong()); - estTimeToNextMarkObject.setText("Next mark: " + timeToNextMark); + // TODO: 21/05/17 make a nice way of checking for this to be null + estTimeToNextMarkObject.setText("Next mark: null"); + if (boat.getEstimateTimeAtNextMark() != null) { + String timeToNextMark = format + .format( + boat.getEstimateTimeAtNextMark() - StreamParser.getCurrentTimeLong()); + estTimeToNextMarkObject.setText("Next mark: " + timeToNextMark); + } // elapsed time if (boat.getMarkRoundingTime() != null) { String elapsedTime = format From 68a243725b0de8fb10e1c48a75b6aacd8dd5c72f Mon Sep 17 00:00:00 2001 From: cir27 Date: Mon, 22 May 2017 05:39:36 +1200 Subject: [PATCH 24/32] Fixed a bug where an error was caused when attempting to flip the race around the prime meridian. All x values are now flipped horizontally if the difference between the smallest lon, e.g. -179.5 and the largest e.g. 179.5 is greater than 180. #story[923] #bug --- .../seng302/controllers/CanvasController.java | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/main/java/seng302/controllers/CanvasController.java b/src/main/java/seng302/controllers/CanvasController.java index 9a2a9797..720f89bd 100644 --- a/src/main/java/seng302/controllers/CanvasController.java +++ b/src/main/java/seng302/controllers/CanvasController.java @@ -50,6 +50,7 @@ public class CanvasController { private final int RHS_BUFFER = BUFFER_SIZE + MARK_SIZE / 2; private final int TOP_BUFFER = BUFFER_SIZE; private final int BOT_BUFFER = TOP_BUFFER + MARK_SIZE / 2; + private boolean horizontalInversion = false; private double distanceScaleFactor; private ScaleDirection scaleDirection; @@ -128,7 +129,6 @@ public class CanvasController { } // TODO: 1/05/17 cir27 - Make the RaceObjects update on the actual delay. - elapsedNanos = 1000 / 60; updateRaceObjects(); if (StreamParser.isRaceFinished()) { this.stop(); @@ -386,16 +386,11 @@ public class CanvasController { //If the course is on a point on the earth where longitudes wrap around. Limit minLonMark = sortedPoints.get(0); Limit maxLonMark = sortedPoints.get(sortedPoints.size()-1); - SingleMark thisMinLon = new SingleMark(minLonMark.toString(), minLonMark.getLat(), minLonMark.getLng(), minLonMark.getSeqID()); - SingleMark thisMaxLon = new SingleMark(maxLonMark.toString(), maxLonMark.getLat(), maxLonMark.getLng(), maxLonMark.getSeqID()); - // TODO: 30/03/17 cir27 - Correctly account for longitude wrapping around. - if (thisMaxLon.getLongitude() - thisMinLon.getLongitude() > 180) { - SingleMark temp = thisMinLon; - thisMinLon = thisMaxLon; - thisMaxLon = temp; + minLonPoint = new SingleMark(minLonMark.toString(), minLonMark.getLat(), minLonMark.getLng(), minLonMark.getSeqID()); + minLatPoint = new SingleMark(maxLonMark.toString(), maxLonMark.getLat(), maxLonMark.getLng(), maxLonMark.getSeqID()); + if (maxLonPoint.getLongitude() - minLonPoint.getLongitude() > 180) { + horizontalInversion = true; } - minLonPoint = thisMinLon; - maxLonPoint = thisMaxLon; } /** @@ -426,6 +421,9 @@ public class CanvasController { referencePointX += distanceScaleFactor * Math.sin(referenceAngle) * Mark.calculateDistance(referencePoint, minLonPoint); referencePointX += ((CANVAS_WIDTH - (LHS_BUFFER + RHS_BUFFER)) - (minLonToMaxLon * distanceScaleFactor)) / 2; } + if(horizontalInversion) { + referencePointX = CANVAS_WIDTH - RHS_BUFFER - (referencePointX - LHS_BUFFER); + } } /** @@ -509,6 +507,9 @@ public class CanvasController { xAxisLocation -= (int) Math.round(distanceScaleFactor * Math.cos(angleFromReference) * distanceFromReference); yAxisLocation += (int) Math.round(distanceScaleFactor * Math.sin(angleFromReference) * distanceFromReference); } + if(horizontalInversion) { + xAxisLocation = CANVAS_WIDTH - RHS_BUFFER - (xAxisLocation - LHS_BUFFER); + } return new Point2D(xAxisLocation, yAxisLocation); } From 97f1ccb6c1de5cea8b0fc3f03d8a01fd8563979a Mon Sep 17 00:00:00 2001 From: cir27 Date: Mon, 22 May 2017 05:41:57 +1200 Subject: [PATCH 25/32] Fixed a bug where an error was caused when attempting to flip the race around the prime meridian. All x values are now flipped horizontally if the difference between the smallest lon, e.g. -179.5 and the largest e.g. 179.5 is greater than 180. #story[923] #bug --- src/main/java/seng302/models/Race.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/seng302/models/Race.java b/src/main/java/seng302/models/Race.java index e78b602a..f69913a5 100644 --- a/src/main/java/seng302/models/Race.java +++ b/src/main/java/seng302/models/Race.java @@ -152,7 +152,7 @@ public class Race { /** * Set a boat as finished - * @param boat The boat that has finished the race/home/cosc/student/wmu16 + * @param boat The boat that has finished the race */ public void setBoatFinished(Yacht boat){ this.finishingOrder.add(boat); From be633c0e60b4b5a73c3eb25c94abac8700c60bd0 Mon Sep 17 00:00:00 2001 From: alistairjmcintyre Date: Mon, 22 May 2017 13:22:55 +1200 Subject: [PATCH 26/32] Marks display correctly on the canvas, no double ups or anything like that left. #[issue10] --- src/main/java/seng302/App.java | 2 +- .../seng302/controllers/CanvasController.java | 3 ++- .../java/seng302/models/mark/GateMark.java | 2 -- .../java/seng302/models/mark/MarkGroup.java | 1 + .../java/seng302/models/mark/SingleMark.java | 1 - .../java/seng302/models/stream/XMLParser.java | 19 ++++++++++++++++--- 6 files changed, 20 insertions(+), 8 deletions(-) diff --git a/src/main/java/seng302/App.java b/src/main/java/seng302/App.java index 28d7e923..c7a764c0 100644 --- a/src/main/java/seng302/App.java +++ b/src/main/java/seng302/App.java @@ -63,7 +63,7 @@ public class App extends Application { //Change the StreamReceiver in this else block to change the default data source. else{ // sr = new StreamReceiver("localhost", 4949, "RaceStream"); - sr = new StreamReceiver("csse-s302staff.canterbury.ac.nz", 4941, "RaceStream"); + sr = new StreamReceiver("localhost", 4949, "RaceStream"); } sr.start(); diff --git a/src/main/java/seng302/controllers/CanvasController.java b/src/main/java/seng302/controllers/CanvasController.java index 40642f41..43c4b40a 100644 --- a/src/main/java/seng302/controllers/CanvasController.java +++ b/src/main/java/seng302/controllers/CanvasController.java @@ -255,7 +255,7 @@ public class CanvasController { private void initializeMarks() { Map allMarks = StreamParser.getXmlObject().getRaceXML().getCompoundMarks(); - + System.out.println(allMarks); for (Mark mark : allMarks.values()) { if (mark.getMarkType() == MarkType.SINGLE_MARK) { SingleMark sMark = (SingleMark) mark; @@ -270,6 +270,7 @@ public class CanvasController { } } group.getChildren().addAll(markGroups); + System.out.println(group.getChildren()); } class ResizableCanvas extends Canvas { diff --git a/src/main/java/seng302/models/mark/GateMark.java b/src/main/java/seng302/models/mark/GateMark.java index ffcf2b51..79943114 100644 --- a/src/main/java/seng302/models/mark/GateMark.java +++ b/src/main/java/seng302/models/mark/GateMark.java @@ -39,12 +39,10 @@ public class GateMark extends Mark { } public double getLatitude(){ - //return (this.getSingleMark1().getLatitude() + this.getSingleMark2().getLatitude()) / 2; return (this.getSingleMark1().getLatitude()); } public double getLongitude(){ - //return (this.getSingleMark1().getLongitude() + this.getSingleMark2().getLongitude()) / 2; return (this.getSingleMark1().getLongitude()); } diff --git a/src/main/java/seng302/models/mark/MarkGroup.java b/src/main/java/seng302/models/mark/MarkGroup.java index ecb0cdc7..c87ae174 100644 --- a/src/main/java/seng302/models/mark/MarkGroup.java +++ b/src/main/java/seng302/models/mark/MarkGroup.java @@ -90,6 +90,7 @@ public class MarkGroup extends Group { { if (mainMark.getMarkType() == MarkType.SINGLE_MARK) { Circle markCircle = (Circle) super.getChildren().get(0); + markCircle.setCenterX(x); markCircle.setCenterY(y); } else { diff --git a/src/main/java/seng302/models/mark/SingleMark.java b/src/main/java/seng302/models/mark/SingleMark.java index d4b4f3f2..9239552a 100644 --- a/src/main/java/seng302/models/mark/SingleMark.java +++ b/src/main/java/seng302/models/mark/SingleMark.java @@ -11,7 +11,6 @@ public class SingleMark extends Mark { private String name; private int id; - /** * Represents a marker * diff --git a/src/main/java/seng302/models/stream/XMLParser.java b/src/main/java/seng302/models/stream/XMLParser.java index 53bb0889..19f9b9db 100644 --- a/src/main/java/seng302/models/stream/XMLParser.java +++ b/src/main/java/seng302/models/stream/XMLParser.java @@ -239,6 +239,9 @@ public class XMLParser { private ArrayList compoundMarkSequence; private ArrayList courseLimit; + // ensures there's no duplicate marks. + private List seenSourceIDs = new ArrayList(); + /** * Constructor for a RaceXMLObject. * Takes the information from a Document object and creates a more usable format. @@ -312,6 +315,7 @@ public class XMLParser { private Map createCompoundMarks(Element docEle) { Map cMarks = new HashMap<>(); + NodeList cMarkList = docEle.getElementsByTagName("Course").item(0).getChildNodes(); for (int i = 0; i < cMarkList.getLength(); i++) { Node cMarkNode = cMarkList.item(i); @@ -319,14 +323,15 @@ public class XMLParser { if (cMarkNode.getNodeName().equals("CompoundMark")) { Integer markID = getNodeAttributeInt(cMarkNode, "CompoundMarkID"); Mark mark = createMark(cMarkNode); - - cMarks.put(markID, mark); + if (mark != null) { + cMarks.put(markID, mark); + } } } - return cMarks; } + private Mark createMark(Node compoundMark) { List marksList = new ArrayList<>(); @@ -348,6 +353,14 @@ public class XMLParser { } } + for (SingleMark mark : marksList) { + if (seenSourceIDs.contains(mark.getId())) { + return null; + } else { + seenSourceIDs.add(mark.getId()); + } + } + if (marksList.size() == 1) { return marksList.get(0); } else if (marksList.size() == 2) { From 80528c9c421362186606dc16e6d37986f85e8c05 Mon Sep 17 00:00:00 2001 From: Calum Date: Mon, 22 May 2017 14:30:31 +1200 Subject: [PATCH 27/32] fixed bug in canvas controller #bug --- src/main/java/seng302/App.java | 3 ++- src/main/java/seng302/controllers/CanvasController.java | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/seng302/App.java b/src/main/java/seng302/App.java index afcd3430..1146fa97 100644 --- a/src/main/java/seng302/App.java +++ b/src/main/java/seng302/App.java @@ -62,8 +62,9 @@ public class App extends Application { } //Change the StreamReceiver in this else block to change the default data source. else{ - //sr = new StreamReceiver("localhost", 4949, "RaceStream"); +// sr = new StreamReceiver("localhost", 4949, "RaceStream"); sr = new StreamReceiver("livedata.americascup.com", 4941, "RaceStream"); +// sr = new StreamReceiver("csse-s302staff.canterbury.ac.nz", 4941, "RaceStream"); } sr.start(); diff --git a/src/main/java/seng302/controllers/CanvasController.java b/src/main/java/seng302/controllers/CanvasController.java index 720f89bd..1dc751f1 100644 --- a/src/main/java/seng302/controllers/CanvasController.java +++ b/src/main/java/seng302/controllers/CanvasController.java @@ -387,7 +387,7 @@ public class CanvasController { Limit minLonMark = sortedPoints.get(0); Limit maxLonMark = sortedPoints.get(sortedPoints.size()-1); minLonPoint = new SingleMark(minLonMark.toString(), minLonMark.getLat(), minLonMark.getLng(), minLonMark.getSeqID()); - minLatPoint = new SingleMark(maxLonMark.toString(), maxLonMark.getLat(), maxLonMark.getLng(), maxLonMark.getSeqID()); + maxLonPoint = new SingleMark(maxLonMark.toString(), maxLonMark.getLat(), maxLonMark.getLng(), maxLonMark.getSeqID()); if (maxLonPoint.getLongitude() - minLonPoint.getLongitude() > 180) { horizontalInversion = true; } From 0367805f0fbef312b976940deff67bac1dc51070 Mon Sep 17 00:00:00 2001 From: Peter Galloway Date: Mon, 22 May 2017 15:01:04 +1200 Subject: [PATCH 28/32] fixed bug from merge where est time to next mark was null on some boats #story[923] --- .../seng302/controllers/StartScreenController.java | 4 ++-- src/main/java/seng302/models/BoatGroup.java | 11 +++++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/main/java/seng302/controllers/StartScreenController.java b/src/main/java/seng302/controllers/StartScreenController.java index bf1456a8..debeb371 100644 --- a/src/main/java/seng302/controllers/StartScreenController.java +++ b/src/main/java/seng302/controllers/StartScreenController.java @@ -58,10 +58,10 @@ public class StartScreenController implements Initializable { contentPane.getChildren().addAll((Pane) FXMLLoader.load(getClass().getResource(jfxUrl))); } catch(javafx.fxml.LoadException e){ - System.err.println(e.getCause()); + e.printStackTrace(); } catch(IOException e){ - System.err.println(e); + e.printStackTrace(); } } diff --git a/src/main/java/seng302/models/BoatGroup.java b/src/main/java/seng302/models/BoatGroup.java index 6a6c0370..9ce9db91 100644 --- a/src/main/java/seng302/models/BoatGroup.java +++ b/src/main/java/seng302/models/BoatGroup.java @@ -217,11 +217,14 @@ public class BoatGroup extends Group{ if (estTimeToNextMarkObject == null){ estTimeToNextMarkObject = getTextObject("", textColor); } - - DateFormat format = new SimpleDateFormat("mm:ss"); - String timeToNextMark = format + if (boat.getEstimateTimeAtNextMark() != null){ + DateFormat format = new SimpleDateFormat("mm:ss"); + String timeToNextMark = format .format(boat.getEstimateTimeAtNextMark() - StreamParser.getCurrentTimeLong()); - estTimeToNextMarkObject.setText("Next mark: " + timeToNextMark); + estTimeToNextMarkObject.setText("Next mark: " + timeToNextMark); + } else { + estTimeToNextMarkObject.setText("Next mark: -"); + } } /** From 78573fa837863fdb286416b33df165f773402ec8 Mon Sep 17 00:00:00 2001 From: Alistair McIntyre Date: Mon, 22 May 2017 15:10:05 +1200 Subject: [PATCH 29/32] Made start/finish lines a different color. #story[923] --- src/main/java/seng302/App.java | 2 +- .../seng302/controllers/CanvasController.java | 5 ++--- .../java/seng302/models/stream/XMLParser.java | 18 ++++++++++-------- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/main/java/seng302/App.java b/src/main/java/seng302/App.java index c7a764c0..28d7e923 100644 --- a/src/main/java/seng302/App.java +++ b/src/main/java/seng302/App.java @@ -63,7 +63,7 @@ public class App extends Application { //Change the StreamReceiver in this else block to change the default data source. else{ // sr = new StreamReceiver("localhost", 4949, "RaceStream"); - sr = new StreamReceiver("localhost", 4949, "RaceStream"); + sr = new StreamReceiver("csse-s302staff.canterbury.ac.nz", 4941, "RaceStream"); } sr.start(); diff --git a/src/main/java/seng302/controllers/CanvasController.java b/src/main/java/seng302/controllers/CanvasController.java index 43c4b40a..398cc712 100644 --- a/src/main/java/seng302/controllers/CanvasController.java +++ b/src/main/java/seng302/controllers/CanvasController.java @@ -254,9 +254,9 @@ public class CanvasController { } private void initializeMarks() { - Map allMarks = StreamParser.getXmlObject().getRaceXML().getCompoundMarks(); + ArrayList allMarks = StreamParser.getXmlObject().getRaceXML().getCompoundMarks(); System.out.println(allMarks); - for (Mark mark : allMarks.values()) { + for (Mark mark : allMarks) { if (mark.getMarkType() == MarkType.SINGLE_MARK) { SingleMark sMark = (SingleMark) mark; @@ -270,7 +270,6 @@ public class CanvasController { } } group.getChildren().addAll(markGroups); - System.out.println(group.getChildren()); } class ResizableCanvas extends Canvas { diff --git a/src/main/java/seng302/models/stream/XMLParser.java b/src/main/java/seng302/models/stream/XMLParser.java index 19f9b9db..97dfe37a 100644 --- a/src/main/java/seng302/models/stream/XMLParser.java +++ b/src/main/java/seng302/models/stream/XMLParser.java @@ -235,7 +235,7 @@ public class XMLParser { //Non atomic race attributes private ArrayList participants; - private Map course; + private ArrayList course; private ArrayList compoundMarkSequence; private ArrayList courseLimit; @@ -312,22 +312,24 @@ public class XMLParser { } - private Map createCompoundMarks(Element docEle) { - Map cMarks = new HashMap<>(); - + private ArrayList createCompoundMarks(Element docEle) { + ArrayList cMarks = new ArrayList<>(); NodeList cMarkList = docEle.getElementsByTagName("Course").item(0).getChildNodes(); for (int i = 0; i < cMarkList.getLength(); i++) { Node cMarkNode = cMarkList.item(i); - if (cMarkNode.getNodeName().equals("CompoundMark")) { - Integer markID = getNodeAttributeInt(cMarkNode, "CompoundMarkID"); Mark mark = createMark(cMarkNode); if (mark != null) { - cMarks.put(markID, mark); + cMarks.add(mark); } } } + + // This is awful but it works. + cMarks.get(0).setName("Start"); + cMarks.get(cMarks.size()-1).setName("Finish"); + return cMarks; } @@ -397,7 +399,7 @@ public class XMLParser { return participants; } - public Map getCompoundMarks() { + public ArrayList getCompoundMarks() { return course; } From c30629542be84df83ebc3b735a72e4cc77715015 Mon Sep 17 00:00:00 2001 From: Alistair McIntyre Date: Mon, 22 May 2017 15:27:23 +1200 Subject: [PATCH 30/32] Merged develop into issue10 branch. Fixed merge issues and completed manual testing before merge request. #story[923] --- src/main/java/seng302/controllers/CanvasController.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/java/seng302/controllers/CanvasController.java b/src/main/java/seng302/controllers/CanvasController.java index 4850b4f4..2884de27 100644 --- a/src/main/java/seng302/controllers/CanvasController.java +++ b/src/main/java/seng302/controllers/CanvasController.java @@ -189,8 +189,8 @@ public class CanvasController { boatGroup.move(); } for (MarkGroup markGroup : markGroups) { - for (int id : markGroup.getRaceIds()) { - if (StreamParser.boatPositions.containsKey(id)) { + for (Long id : markGroup.getRaceIds()) { + if (StreamParser.markPositions.containsKey(id)) { updateMarkGroup(id, markGroup); } } @@ -224,8 +224,8 @@ public class CanvasController { } } - void updateMarkGroup (int raceId, MarkGroup markGroup) { - PriorityBlockingQueue movementQueue = StreamParser.boatPositions.get(raceId); + void updateMarkGroup (long raceId, MarkGroup markGroup) { + PriorityBlockingQueue movementQueue = StreamParser.markPositions.get(raceId); if (movementQueue.size() > 0){ try { BoatPositionPacket positionPacket = movementQueue.take(); @@ -256,7 +256,6 @@ public class CanvasController { private void initializeMarks() { ArrayList allMarks = StreamParser.getXmlObject().getRaceXML().getCompoundMarks(); - System.out.println(allMarks); for (Mark mark : allMarks) { if (mark.getMarkType() == MarkType.SINGLE_MARK) { SingleMark sMark = (SingleMark) mark; From e51c9669691141c6bbc9a5c3d85ff2703a3567b8 Mon Sep 17 00:00:00 2001 From: Alistair McIntyre Date: Mon, 22 May 2017 16:05:24 +1200 Subject: [PATCH 31/32] Made sure only boats in participant list are replaced. Also removed mark coloring as it wasn't as accurate as was necessary. #story[923] --- src/main/java/seng302/App.java | 2 +- .../seng302/controllers/CanvasController.java | 17 +++++++++++++---- .../seng302/models/stream/StreamParser.java | 1 + .../java/seng302/models/stream/XMLParser.java | 4 ---- 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/main/java/seng302/App.java b/src/main/java/seng302/App.java index 28d7e923..ac264db6 100644 --- a/src/main/java/seng302/App.java +++ b/src/main/java/seng302/App.java @@ -63,7 +63,7 @@ public class App extends Application { //Change the StreamReceiver in this else block to change the default data source. else{ // sr = new StreamReceiver("localhost", 4949, "RaceStream"); - sr = new StreamReceiver("csse-s302staff.canterbury.ac.nz", 4941, "RaceStream"); + sr = new StreamReceiver("livedata.americascup.com", 4941, "RaceStream"); } sr.start(); diff --git a/src/main/java/seng302/controllers/CanvasController.java b/src/main/java/seng302/controllers/CanvasController.java index 2884de27..0bdeae25 100644 --- a/src/main/java/seng302/controllers/CanvasController.java +++ b/src/main/java/seng302/controllers/CanvasController.java @@ -26,6 +26,7 @@ import seng302.models.mark.SingleMark; import seng302.models.stream.StreamParser; import seng302.models.stream.XMLParser; import seng302.models.stream.XMLParser.RaceXMLObject.Limit; +import seng302.models.stream.XMLParser.RaceXMLObject.Participant; import seng302.models.stream.packets.BoatPositionPacket; /** @@ -244,11 +245,19 @@ public class CanvasController { Map boats = StreamParser.getBoats(); Group boatAnnotations = new Group(); + ArrayList participants = StreamParser.getXmlObject().getRaceXML().getParticipants(); + ArrayList participantIDs = new ArrayList<>(); + for (Participant p : participants) { + participantIDs.add(p.getsourceID()); + } + for (Yacht boat : boats.values()) { - boat.setColour(Colors.getColor()); - BoatGroup boatGroup = new BoatGroup(boat, boat.getColour()); - boatGroups.add(boatGroup); - boatAnnotations.getChildren().add(boatGroup.getLowPriorityAnnotations()); + if (participantIDs.contains(boat.getSourceID())) { + boat.setColour(Colors.getColor()); + BoatGroup boatGroup = new BoatGroup(boat, boat.getColour()); + boatGroups.add(boatGroup); + boatAnnotations.getChildren().add(boatGroup.getLowPriorityAnnotations()); + } } group.getChildren().add(boatAnnotations); group.getChildren().addAll(boatGroups); diff --git a/src/main/java/seng302/models/stream/StreamParser.java b/src/main/java/seng302/models/stream/StreamParser.java index 0b685da2..f800379c 100644 --- a/src/main/java/seng302/models/stream/StreamParser.java +++ b/src/main/java/seng302/models/stream/StreamParser.java @@ -307,6 +307,7 @@ public class StreamParser extends Thread{ boats = xmlObject.getBoatXML().getCompetingBoats(); } if (messageType == 6) { //6 is race info xml + newRaceXmlReceived = true; } } diff --git a/src/main/java/seng302/models/stream/XMLParser.java b/src/main/java/seng302/models/stream/XMLParser.java index 97dfe37a..674a2611 100644 --- a/src/main/java/seng302/models/stream/XMLParser.java +++ b/src/main/java/seng302/models/stream/XMLParser.java @@ -326,10 +326,6 @@ public class XMLParser { } } - // This is awful but it works. - cMarks.get(0).setName("Start"); - cMarks.get(cMarks.size()-1).setName("Finish"); - return cMarks; } From 6f1b0b06c3d28a72312c0af5614db1a4bc7ae22a Mon Sep 17 00:00:00 2001 From: Zhi You Tan Date: Mon, 22 May 2017 16:17:52 +1200 Subject: [PATCH 32/32] Fixed est time to next mark and time from last mark annotation update after commit e0750f53 in BoatGroup.java #story[924] #story[927] --- src/main/java/seng302/models/BoatGroup.java | 168 +++++++++++--------- 1 file changed, 90 insertions(+), 78 deletions(-) diff --git a/src/main/java/seng302/models/BoatGroup.java b/src/main/java/seng302/models/BoatGroup.java index 9ce9db91..3e97df5e 100644 --- a/src/main/java/seng302/models/BoatGroup.java +++ b/src/main/java/seng302/models/BoatGroup.java @@ -18,13 +18,14 @@ import java.text.DateFormat; import java.text.SimpleDateFormat; /** - * BoatGroup is a javafx group that by default contains a graphical objects for representing a 2 dimensional boat. - * It contains a single polygon for the boat, a group of lines to show it's path, a wake object and two text labels to - * annotate the boat teams name and the boats velocity. The boat will update it's position onscreen everytime - * UpdatePosition is called unless the window is minimized in which case it attempts to store animations and apply them - * when the window is maximised. + * BoatGroup is a javafx group that by default contains a graphical objects for representing a 2 + * dimensional boat. It contains a single polygon for the boat, a group of lines to show it's path, + * a wake object and two text labels to annotate the boat teams name and the boats velocity. The + * boat will update it's position onscreen everytime UpdatePosition is called unless the window is + * minimized in which case it attempts to store animations and apply them when the window is + * maximised. */ -public class BoatGroup extends Group{ +public class BoatGroup extends Group { //Constants for drawing private static final double TEAMNAME_X_OFFSET = 10d; @@ -62,36 +63,40 @@ public class BoatGroup extends Group{ /** * Creates a BoatGroup with the default triangular boat polygon. - * @param boat The boat that the BoatGroup will represent. Must contain an ID which will be used to tell which - * BoatGroup to update. + * + * @param boat The boat that the BoatGroup will represent. Must contain an ID which will be used + * to tell which BoatGroup to update. * @param color The colour of the boat polygon and the trailing line. */ - public BoatGroup (Yacht boat, Color color){ + public BoatGroup(Yacht boat, Color color) { this.boat = boat; initChildren(color); this.textColor = color; } /** - * Creates a BoatGroup with the boat being the default polygon. The head of the boat should be at point (0,0). - * @param boat The boat that the BoatGroup will represent. Must contain an ID which will be used to tell which - * BoatGroup to update. + * Creates a BoatGroup with the boat being the default polygon. The head of the boat should be + * at point (0,0). + * + * @param boat The boat that the BoatGroup will represent. Must contain an ID which will be used + * to tell which BoatGroup to update. * @param color The colour of the boat polygon and the trailing line. - * @param points An array of co-ordinates x1,y1,x2,y2,x3,y3... that will make up the boat polygon. + * @param points An array of co-ordinates x1,y1,x2,y2,x3,y3... that will make up the boat + * polygon. */ - public BoatGroup (Yacht boat, Color color, double... points) - { + public BoatGroup(Yacht boat, Color color, double... points) { this.boat = boat; initChildren(color, points); } /** * Return a text object with caching and a color applied + * * @param defaultText The default text to display * @param fill The text fill color * @return The text object */ - private Text getTextObject(String defaultText, Color fill){ + private Text getTextObject(String defaultText, Color fill) { Text text = new Text(defaultText); text.setFill(fill); @@ -103,10 +108,12 @@ public class BoatGroup extends Group{ /** * Creates the javafx objects that will be the in the group by default. + * * @param color The colour of the boat polygon and the trailing line. - * @param points An array of co-ordinates x1,y1,x2,y2,x3,y3... that will make up the boat polygon. + * @param points An array of co-ordinates x1,y1,x2,y2,x3,y3... that will make up the boat + * polygon. */ - private void initChildren (Color color, double... points) { + private void initChildren(Color color, double... points) { textColor = color; destinationSet = false; @@ -132,14 +139,14 @@ public class BoatGroup extends Group{ updateLastMarkRoundingTime(); updateTimeTillNextMark(); - if (estTimeToNextMarkObject != null){ + if (estTimeToNextMarkObject != null) { estTimeToNextMarkObject.setX(ESTTIMETONEXTMARK_X_OFFSET); estTimeToNextMarkObject.setY(ESTTIMETONEXTMARK_Y_OFFSET); estTimeToNextMarkObject - .relocate(estTimeToNextMarkObject.getX(), estTimeToNextMarkObject.getY()); + .relocate(estTimeToNextMarkObject.getX(), estTimeToNextMarkObject.getY()); } - if (legTimeObject != null){ + if (legTimeObject != null) { legTimeObject.setX(LEGTIME_X_OFFSET); legTimeObject.setY(LEGTIME_Y_OFFSET); legTimeObject.relocate(legTimeObject.getX(), legTimeObject.getY()); @@ -148,15 +155,16 @@ public class BoatGroup extends Group{ wake = new Wake(0, -BOAT_HEIGHT); super.getChildren() - .addAll(teamNameObject, velocityObject, boatPoly, estTimeToNextMarkObject, - legTimeObject); + .addAll(teamNameObject, velocityObject, boatPoly, estTimeToNextMarkObject, + legTimeObject); } /** * Creates the javafx objects that will be the in the group by default. + * * @param color The colour of the boat polygon and the trailing line. */ - private void initChildren (Color color) { + private void initChildren(Color color) { initChildren(color, -BOAT_WIDTH / 2, BOAT_HEIGHT / 2, 0.0, -BOAT_HEIGHT / 2, @@ -164,7 +172,9 @@ public class BoatGroup extends Group{ } /** - * Moves the boat and its children annotations from its current coordinates by specified amounts. + * Moves the boat and its children annotations from its current coordinates by specified + * amounts. + * * @param dx The amount to move the X coordinate by * @param dy The amount to move the Y coordinate by */ @@ -186,6 +196,7 @@ public class BoatGroup extends Group{ /** * Moves the boat and its children annotations to coordinates specified + * * @param x The X coordinate to move the boat to * @param y The Y coordinate to move the boat to */ @@ -213,11 +224,11 @@ public class BoatGroup extends Group{ /** * Updates the time until next mark label, will create a label if one doesn't exist */ - private void updateTimeTillNextMark(){ - if (estTimeToNextMarkObject == null){ - estTimeToNextMarkObject = getTextObject("", textColor); + private void updateTimeTillNextMark() { + if (estTimeToNextMarkObject == null) { + estTimeToNextMarkObject = getTextObject("Next mark: -", textColor); } - if (boat.getEstimateTimeAtNextMark() != null){ + if (boat.getEstimateTimeAtNextMark() != null) { DateFormat format = new SimpleDateFormat("mm:ss"); String timeToNextMark = format .format(boat.getEstimateTimeAtNextMark() - StreamParser.getCurrentTimeLong()); @@ -230,18 +241,17 @@ public class BoatGroup extends Group{ /** * Updates the time since last mark rounding, will create a label if one doesn't exist */ - private void updateLastMarkRoundingTime(){ - if (legTimeObject == null){ - legTimeObject = getTextObject("", textColor); + private void updateLastMarkRoundingTime() { + if (legTimeObject == null) { + legTimeObject = getTextObject("Last mark: -", textColor); } - if (boat.getMarkRoundingTime() != null){ + if (boat.getMarkRoundingTime() != null) { DateFormat format = new SimpleDateFormat("mm:ss"); String elapsedTime = format - .format(StreamParser.getCurrentTimeLong() - boat.getMarkRoundingTime()); + .format(StreamParser.getCurrentTimeLong() - boat.getMarkRoundingTime()); legTimeObject.setText("Last mark: " + elapsedTime); - } - else{ + } else { legTimeObject.setText("Last mark: -"); } @@ -255,19 +265,19 @@ public class BoatGroup extends Group{ moveGroupBy(xIncrement, yIncrement); framesToMove = framesToMove - 1; - if (framesToMove <= 0){ + if (framesToMove <= 0) { isStopped = true; } - if (distanceTravelled > 70){ + if (distanceTravelled > 70) { distanceTravelled = 0d; - if (lastPoint != null){ + if (lastPoint != null) { Line l = new Line( - lastPoint.getX(), - lastPoint.getY(), - boatPoly.getLayoutX(), - boatPoly.getLayoutY() + lastPoint.getX(), + lastPoint.getY(), + boatPoly.getLayoutX(), + boatPoly.getLayoutY() ); l.getStrokeDashArray().setAll(3d, 7d); l.setStroke(boat.getColour()); @@ -276,56 +286,59 @@ public class BoatGroup extends Group{ lineGroup.getChildren().add(l); } - if (destinationSet){ + if (destinationSet) { lastPoint = new Point2D(boatPoly.getLayoutX(), boatPoly.getLayoutY()); } } - wake.updatePosition(1000/60); + wake.updatePosition(1000 / 60); } - /** - * Calculates the rotational velocity required to reach the rotationalGoal from the currentRotation. - */ - protected Double calculateRotationalVelocity (Double rotationalGoal) { - Double rotationalVelocity = 0.0; + /** + * Calculates the rotational velocity required to reach the rotationalGoal from the + * currentRotation. + */ + protected Double calculateRotationalVelocity(Double rotationalGoal) { + Double rotationalVelocity = 0.0; - if (Math.abs(rotationalGoal - lastRotation) > 180) { - if (rotationalGoal - lastRotation >= 0.0) { - rotationalVelocity = ((rotationalGoal - lastRotation) - 360) / 200; - } else { - rotationalVelocity = (360 + (rotationalGoal - lastRotation)) / 200; - } - } else { - rotationalVelocity = (rotationalGoal - lastRotation) / 200; + if (Math.abs(rotationalGoal - lastRotation) > 180) { + if (rotationalGoal - lastRotation >= 0.0) { + rotationalVelocity = ((rotationalGoal - lastRotation) - 360) / 200; + } else { + rotationalVelocity = (360 + (rotationalGoal - lastRotation)) / 200; + } + } else { + rotationalVelocity = (rotationalGoal - lastRotation) / 200; + } + + //Sometimes the rotation is too large to be realistic. In that case just do it instantly. + if (Math.abs(rotationalVelocity) > 1) { + rotationalVelocity = 0.0; + } + + return rotationalVelocity; } - //Sometimes the rotation is too large to be realistic. In that case just do it instantly. - if (Math.abs(rotationalVelocity) > 1) { - rotationalVelocity = 0.0; - } - - return rotationalVelocity; - } - /** * Sets the destination of the boat and the headng it should have once it reaches + * * @param newXValue The X co-ordinate the boat needs to move to. * @param newYValue The Y co-ordinate the boat needs to move to. * @param rotation Rotation to move graphics to. * @param timeValid the time the position values are valid for */ - public void setDestination (double newXValue, double newYValue, double rotation, double groundSpeed, long timeValid, double frameRate, long id) { - if (lastTimeValid == 0){ + public void setDestination(double newXValue, double newYValue, double rotation, + double groundSpeed, long timeValid, double frameRate, long id) { + if (lastTimeValid == 0) { lastTimeValid = timeValid - 200; moveTo(newXValue, newYValue, rotation); } - framesToMove = Math.round((frameRate/(1000.0f/(timeValid-lastTimeValid)))); + framesToMove = Math.round((frameRate / (1000.0f / (timeValid - lastTimeValid)))); double dx = newXValue - boatPoly.getLayoutX(); double dy = newYValue - boatPoly.getLayoutY(); - xIncrement = dx/framesToMove; - yIncrement = dy/framesToMove; + xIncrement = dx / framesToMove; + yIncrement = dy / framesToMove; destinationSet = true; @@ -335,8 +348,8 @@ public class BoatGroup extends Group{ updateLastMarkRoundingTime(); if (Math.abs(rotationalVelocity) > 0.075) { - rotationalVelocity = 0.0; - wake.rotate(rotation); + rotationalVelocity = 0.0; + wake.rotate(rotation); } rotateTo(rotation); @@ -361,7 +374,6 @@ public class BoatGroup extends Group{ } - public void setTeamNameObjectVisible(Boolean visible) { teamNameObject.setVisible(visible); } @@ -400,13 +412,13 @@ public class BoatGroup extends Group{ } /** - * Due to javaFX limitations annotations associated with a boat that you want to appear below all boats in the - * Z-axis need to be pulled out of the BoatGroup and added to the parent group of the BoatGroups. This function - * returns these annotations as a group. + * Due to javaFX limitations annotations associated with a boat that you want to appear below + * all boats in the Z-axis need to be pulled out of the BoatGroup and added to the parent group + * of the BoatGroups. This function returns these annotations as a group. * * @return A group containing low priority annotations. */ - public Group getLowPriorityAnnotations () { + public Group getLowPriorityAnnotations() { Group group = new Group(); group.getChildren().addAll(wake, lineGroup); return group;