From acbde5aad87ee798bbb3b78bb094b17ce9d66b17 Mon Sep 17 00:00:00 2001 From: Calum Date: Wed, 24 May 2017 03:09:11 +1200 Subject: [PATCH 01/16] Moved boat annotations into their own class. Implemented observer pattern. Observer pattern appears to have caused issues with updating Text objects. Made annotations look nicer. Kinda. #refactor --- src/main/java/seng302/App.java | 1 + .../seng302/controllers/CanvasController.java | 5 +- .../controllers/RaceViewController.java | 1 + .../seng302/fxObjects/BoatAnnotations.java | 142 +++++++++ .../{models => fxObjects}/BoatGroup.java | 236 ++++++++------- .../{models/mark => fxObjects}/MarkGroup.java | 33 ++- .../seng302/{models => fxObjects}/Wake.java | 6 +- src/main/java/seng302/models/Yacht.java | 276 ++++++++++++++++-- .../seng302/models/stream/StreamParser.java | 2 +- 9 files changed, 543 insertions(+), 159 deletions(-) create mode 100644 src/main/java/seng302/fxObjects/BoatAnnotations.java rename src/main/java/seng302/{models => fxObjects}/BoatGroup.java (66%) rename src/main/java/seng302/{models/mark => fxObjects}/MarkGroup.java (75%) rename src/main/java/seng302/{models => fxObjects}/Wake.java (97%) diff --git a/src/main/java/seng302/App.java b/src/main/java/seng302/App.java index ac264db6..b66376c5 100644 --- a/src/main/java/seng302/App.java +++ b/src/main/java/seng302/App.java @@ -64,6 +64,7 @@ public class App extends Application { 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 0bdeae25..12e29efa 100644 --- a/src/main/java/seng302/controllers/CanvasController.java +++ b/src/main/java/seng302/controllers/CanvasController.java @@ -15,12 +15,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.fxObjects.AnnotationsThingThatNeedsABetterName; +import seng302.fxObjects.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.fxObjects.MarkGroup; import seng302.models.mark.MarkType; import seng302.models.mark.SingleMark; import seng302.models.stream.StreamParser; diff --git a/src/main/java/seng302/controllers/RaceViewController.java b/src/main/java/seng302/controllers/RaceViewController.java index 43c04a9b..f2f60ed5 100644 --- a/src/main/java/seng302/controllers/RaceViewController.java +++ b/src/main/java/seng302/controllers/RaceViewController.java @@ -25,6 +25,7 @@ import seng302.controllers.annotations.Annotation; import seng302.controllers.annotations.ImportantAnnotationController; import seng302.controllers.annotations.ImportantAnnotationDelegate; import seng302.controllers.annotations.ImportantAnnotationsState; +import seng302.fxObjects.BoatGroup; import seng302.models.*; import seng302.models.stream.StreamParser; diff --git a/src/main/java/seng302/fxObjects/BoatAnnotations.java b/src/main/java/seng302/fxObjects/BoatAnnotations.java new file mode 100644 index 00000000..d03d9e47 --- /dev/null +++ b/src/main/java/seng302/fxObjects/BoatAnnotations.java @@ -0,0 +1,142 @@ +package seng302.fxObjects; + +import javafx.scene.CacheHint; +import javafx.scene.Group; +import javafx.scene.Node; +import javafx.scene.paint.Color; +import javafx.scene.shape.Polygon; +import javafx.scene.shape.Rectangle; +import javafx.scene.text.Text; +import seng302.models.Yacht; +import seng302.models.stream.StreamParser; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.List; + +/** + * Created by cir27 on 23/05/17. + */ +public class BoatAnnotations extends Group{ + + private static final double TEAMNAME_X_OFFSET = 18d; + private static final double TEAMNAME_Y_OFFSET = -29d; + private static final double VELOCITY_X_OFFSET = 18d; + private static final double VELOCITY_Y_OFFSET = -17d; + private static final double ESTTIMETONEXTMARK_X_OFFSET = 18d; + private static final double ESTTIMETONEXTMARK_Y_OFFSET = -5d; + private static final double LEGTIME_X_OFFSET = 18d; + private static final double LEGTIME_Y_OFFSET = 7d; + +// private Rectangle background = new Rectangle(); + private Text teamNameObject; + private Text velocityObject; + private Text estTimeToNextMarkObject; + private Text legTimeObject; + private List kids; + + private boolean visible = true; + + BoatAnnotations (Yacht boat, Color theme) { + super.setCache(true); +// background.setX(15d); +// background.setY(-32d); +// background.setWidth(150); +// background.setHeight(55); +// background.setArcHeight(10); +// background.setArcWidth(10); +// background.setFill(new Color(1, 1, 1, 0.75)); +// background.setStroke(theme); +// background.setStrokeWidth(2); +// background.setCache(true); +// background.setCacheHint(CacheHint.SPEED); + + teamNameObject = getTextObject(boat.getShortName(), theme); + teamNameObject.relocate(TEAMNAME_X_OFFSET, TEAMNAME_Y_OFFSET); + + velocityObject = getTextObject("", theme); + velocityObject.relocate(VELOCITY_X_OFFSET, VELOCITY_Y_OFFSET); + //On change listener + boat.getReadOnlyVelocityProperty().addListener((obs, oldVal, newVal) -> + velocityObject.setText(String.format("%.2f m/s", newVal.doubleValue())) + ); + //Invalidation listener + boat.getReadOnlyVelocityProperty().addListener(obs -> + velocityObject.setText("") + ); + + estTimeToNextMarkObject = getTextObject("Next mark: ", theme); + estTimeToNextMarkObject.relocate(ESTTIMETONEXTMARK_X_OFFSET, ESTTIMETONEXTMARK_Y_OFFSET); + boat.getReadOnlyNextMarkProperty().addListener((obs, oldVal, newVal) -> { + DateFormat format = new SimpleDateFormat("mm:ss"); + String timeToNextMark = format + .format(newVal.longValue() - StreamParser.getCurrentTimeLong()); + estTimeToNextMarkObject.setText("Next mark: " + timeToNextMark); + }); + boat.getReadOnlyNextMarkProperty().addListener(obs -> + estTimeToNextMarkObject.setText("Next mark: - ") + ); + + legTimeObject = getTextObject("Last mark: -", theme); + legTimeObject.relocate(LEGTIME_X_OFFSET, LEGTIME_Y_OFFSET); + boat.getReadOnlyMarkRoundingProperty().addListener((obs, oldTime, newTime) -> { + DateFormat format = new SimpleDateFormat("mm:ss"); + String elapsedTime = format + .format(StreamParser.getCurrentTimeLong() - newTime.longValue()); + legTimeObject.setText("Last mark: " + elapsedTime); + }); + boat.getReadOnlyMarkRoundingProperty().addListener(obs -> + legTimeObject.setText("Last mark: - ") + ); + + kids = new ArrayList<>(); +// kids.add(background); + kids.add(velocityObject); + kids.add(teamNameObject); + kids.add(estTimeToNextMarkObject); + kids.add(legTimeObject); + +// super.getChildren().addAll(background, teamNameObject, velocityObject, estTimeToNextMarkObject, legTimeObject); + } + + /** + * 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; + } + + public void setTeamNameObjectVisible(Boolean visible) { + teamNameObject.setVisible(visible); + } + + public void setVelocityObjectVisible(Boolean visible) { + velocityObject.setVisible(visible); + } + + public void setEstTimeToNextMarkObjectVisible(Boolean visible) { + estTimeToNextMarkObject.setVisible(visible); + } + + public void setLegTimeObjectVisible(Boolean visible) { + legTimeObject.setVisible(visible); + } + + public void toggleVisible() { + visible = !visible; + this.setVisible(visible); + } + + public List getkiddies () { + return kids; + } +} diff --git a/src/main/java/seng302/models/BoatGroup.java b/src/main/java/seng302/fxObjects/BoatGroup.java similarity index 66% rename from src/main/java/seng302/models/BoatGroup.java rename to src/main/java/seng302/fxObjects/BoatGroup.java index 3e97df5e..2d659e84 100644 --- a/src/main/java/seng302/models/BoatGroup.java +++ b/src/main/java/seng302/fxObjects/BoatGroup.java @@ -1,9 +1,10 @@ -package seng302.models; +package seng302.fxObjects; import javafx.event.EventHandler; import javafx.geometry.Point2D; import javafx.scene.CacheHint; import javafx.scene.Group; +import javafx.scene.Node; import javafx.scene.input.MouseDragEvent; import javafx.scene.input.MouseEvent; import javafx.scene.paint.Color; @@ -12,6 +13,7 @@ import javafx.scene.shape.Line; import javafx.scene.shape.Polygon; import javafx.scene.text.Text; import javafx.scene.transform.Rotate; +import seng302.models.Yacht; import seng302.models.stream.StreamParser; import java.text.DateFormat; @@ -28,14 +30,6 @@ import java.text.SimpleDateFormat; public class BoatGroup extends Group { //Constants for drawing - private static final double TEAMNAME_X_OFFSET = 10d; - private static final double TEAMNAME_Y_OFFSET = -29d; - private static final double VELOCITY_X_OFFSET = 10d; - 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. @@ -49,16 +43,14 @@ public class BoatGroup extends Group { private Yacht boat; private Group lineGroup = new Group(); private Polygon boatPoly; - private Text teamNameObject; - private Text velocityObject; - 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 BoatAnnotations boatAnnotations; + private Boolean isSelected = true; //All boats are initalised as selected /** @@ -89,22 +81,22 @@ 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; - } +// /** +// * 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. @@ -119,44 +111,51 @@ public class BoatGroup extends Group { boatPoly = new Polygon(points); boatPoly.setFill(color); - boatPoly.setOnMouseEntered(event -> boatPoly.setFill(Color.FLORALWHITE)); - boatPoly.setOnMouseExited(event -> boatPoly.setFill(color)); + boatPoly.setOnMouseEntered(event -> { + boatPoly.setFill(Color.FLORALWHITE); + boatPoly.setStroke(Color.RED); + }); + boatPoly.setOnMouseExited(event -> { + boatPoly.setFill(color); + boatPoly.setStroke(Color.BLACK); + }); boatPoly.setOnMouseClicked(event -> setIsSelected(!isSelected)); boatPoly.setCache(true); boatPoly.setCacheHint(CacheHint.SPEED); - teamNameObject = getTextObject(boat.getShortName(), textColor); - velocityObject = getTextObject(boat.getVelocity().toString(), textColor); +// teamNameObject = getTextObject(boat.getShortName(), textColor); +// velocityObject = getTextObject(boat.getVelocity().toString(), textColor); +// +// teamNameObject.setX(TEAMNAME_X_OFFSET); +// teamNameObject.setY(TEAMNAME_Y_OFFSET); +// teamNameObject.relocate(teamNameObject.getX(), teamNameObject.getY()); +// +// velocityObject.setX(VELOCITY_X_OFFSET); +// velocityObject.setY(VELOCITY_Y_OFFSET); +// velocityObject.relocate(velocityObject.getX(), velocityObject.getY()); +//// +//// updateLastMarkRoundingTime(); +//// updateTimeTillNextMark(); +// +// 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()); +// +// } - teamNameObject.setX(TEAMNAME_X_OFFSET); - teamNameObject.setY(TEAMNAME_Y_OFFSET); - teamNameObject.relocate(teamNameObject.getX(), teamNameObject.getY()); - - velocityObject.setX(VELOCITY_X_OFFSET); - velocityObject.setY(VELOCITY_Y_OFFSET); - velocityObject.relocate(velocityObject.getX(), velocityObject.getY()); - - updateLastMarkRoundingTime(); - updateTimeTillNextMark(); - - 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()); - - } + boatAnnotations = new BoatAnnotations(boat, color); wake = new Wake(0, -BOAT_HEIGHT); - super.getChildren() - .addAll(teamNameObject, velocityObject, boatPoly, estTimeToNextMarkObject, - legTimeObject); + super.getChildren().addAll(boatPoly); + super.getChildren().addAll(boatAnnotations.getkiddies()); } /** @@ -181,14 +180,12 @@ public class BoatGroup extends Group { private void moveGroupBy(double dx, double dy) { boatPoly.setLayoutX(boatPoly.getLayoutX() + dx); boatPoly.setLayoutY(boatPoly.getLayoutY() + dy); - teamNameObject.setLayoutX(teamNameObject.getLayoutX() + dx); - 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); +// boatAnnotations.setLayoutX(boatAnnotations.getLayoutX() + dx); +// boatAnnotations.setLayoutY(boatAnnotations.getLayoutY() + dy); + for (Node node : boatAnnotations.getkiddies()) { + node.setLayoutX(node.getLayoutX() + dx); + node.setLayoutY(node.getLayoutY() + dy); + } wake.setLayoutX(wake.getLayoutX() + dx); wake.setLayoutY(wake.getLayoutY() + dy); } @@ -204,14 +201,14 @@ public class BoatGroup extends Group { rotateTo(rotation); boatPoly.setLayoutX(x); boatPoly.setLayoutY(y); - teamNameObject.setLayoutX(x); - teamNameObject.setLayoutY(y); - velocityObject.setLayoutX(x); - velocityObject.setLayoutY(y); - estTimeToNextMarkObject.setLayoutX(x); - estTimeToNextMarkObject.setLayoutY(y); - legTimeObject.setLayoutX(x); - legTimeObject.setLayoutY(y); +// boatAnnotations.setLayoutX(x); +// boatAnnotations.setLayoutY(y); + int i = 0; + for (Node n : boatAnnotations.getkiddies()) { + n.setLayoutX(x + 10 + i); + n.setLayoutY(y + 10 + i); + i += 10; + } wake.setLayoutX(x); wake.setLayoutY(y); wake.rotate(rotation); @@ -221,41 +218,41 @@ public class BoatGroup extends Group { 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("Next mark: -", textColor); - } - if (boat.getEstimateTimeAtNextMark() != null) { - DateFormat format = new SimpleDateFormat("mm:ss"); - String timeToNextMark = format - .format(boat.getEstimateTimeAtNextMark() - StreamParser.getCurrentTimeLong()); - estTimeToNextMarkObject.setText("Next mark: " + timeToNextMark); - } else { - estTimeToNextMarkObject.setText("Next mark: -"); - } - } +// /** +// * Updates the time until next mark label, will create a label if one doesn't exist +// */ +// private void updateTimeTillNextMark() { +// if (estTimeToNextMarkObject == null) { +// estTimeToNextMarkObject = getTextObject("Next mark: -", textColor); +// } +// if (boat.getEstimateTimeAtNextMark() != null) { +// DateFormat format = new SimpleDateFormat("mm:ss"); +// String timeToNextMark = format +// .format(boat.getEstimateTimeAtNextMark() - StreamParser.getCurrentTimeLong()); +// estTimeToNextMarkObject.setText("Next mark: " + timeToNextMark); +// } else { +// estTimeToNextMarkObject.setText("Next mark: -"); +// } +// } - /** - * Updates the time since last mark rounding, will create a label if one doesn't exist - */ - private void updateLastMarkRoundingTime() { - if (legTimeObject == null) { - legTimeObject = getTextObject("Last mark: -", 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: -"); - - } - } +// /** +// * Updates the time since last mark rounding, will create a label if one doesn't exist +// */ +// private void updateLastMarkRoundingTime() { +// if (legTimeObject == null) { +// legTimeObject = getTextObject("Last mark: -", 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; @@ -298,7 +295,7 @@ public class BoatGroup extends Group { * Calculates the rotational velocity required to reach the rotationalGoal from the * currentRotation. */ - protected Double calculateRotationalVelocity(Double rotationalGoal) { + private Double calculateRotationalVelocity(Double rotationalGoal) { Double rotationalVelocity = 0.0; if (Math.abs(rotationalGoal - lastRotation) > 180) { @@ -344,8 +341,8 @@ public class BoatGroup extends Group { Double rotationalVelocity = calculateRotationalVelocity(rotation); - updateTimeTillNextMark(); - updateLastMarkRoundingTime(); +// updateTimeTillNextMark(); +// updateLastMarkRoundingTime(); if (Math.abs(rotationalVelocity) > 0.075) { rotationalVelocity = 0.0; @@ -353,12 +350,10 @@ public class BoatGroup extends Group { } rotateTo(rotation); + boat.setVelocity(groundSpeed); wake.setRotationalVelocity(rotationalVelocity, groundSpeed); - - velocityObject.setText(String.format("%.2f m/s", groundSpeed)); lastTimeValid = timeValid; isStopped = false; - lastRotation = rotation; } @@ -371,23 +366,24 @@ public class BoatGroup extends Group { setWakeVisible(isSelected); setEstTimeToNextMarkObjectVisible(isSelected); setLegTimeObjectVisible(isSelected); + boatAnnotations.setVisible(isSelected); } public void setTeamNameObjectVisible(Boolean visible) { - teamNameObject.setVisible(visible); + boatAnnotations.setTeamNameObjectVisible(visible); } public void setVelocityObjectVisible(Boolean visible) { - velocityObject.setVisible(visible); + boatAnnotations.setVelocityObjectVisible(visible); } public void setEstTimeToNextMarkObjectVisible(Boolean visible) { - estTimeToNextMarkObject.setVisible(visible); + boatAnnotations.setEstTimeToNextMarkObjectVisible(visible); } public void setLegTimeObjectVisible(Boolean visible) { - legTimeObject.setVisible(visible); + boatAnnotations.setLegTimeObjectVisible(visible); } public void setLineGroupVisible(Boolean visible) { diff --git a/src/main/java/seng302/models/mark/MarkGroup.java b/src/main/java/seng302/fxObjects/MarkGroup.java similarity index 75% rename from src/main/java/seng302/models/mark/MarkGroup.java rename to src/main/java/seng302/fxObjects/MarkGroup.java index c87ae174..464743c9 100644 --- a/src/main/java/seng302/models/mark/MarkGroup.java +++ b/src/main/java/seng302/fxObjects/MarkGroup.java @@ -1,4 +1,4 @@ -package seng302.models.mark; +package seng302.fxObjects; import java.util.ArrayList; import java.util.List; @@ -7,6 +7,10 @@ import javafx.scene.Group; import javafx.scene.paint.Color; import javafx.scene.shape.Circle; import javafx.scene.shape.Line; +import seng302.models.mark.GateMark; +import seng302.models.mark.Mark; +import seng302.models.mark.MarkType; +import seng302.models.mark.SingleMark; /** * Created by CJIRWIN on 26/04/2017. @@ -90,23 +94,28 @@ public class MarkGroup extends Group { { if (mainMark.getMarkType() == MarkType.SINGLE_MARK) { Circle markCircle = (Circle) super.getChildren().get(0); - - markCircle.setCenterX(x); - markCircle.setCenterY(y); + if (Math.abs(markCircle.getCenterX() - x) > 5 || Math.abs(markCircle.getCenterY() - y) > 5) { + markCircle.setCenterX(x); + markCircle.setCenterY(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(0).getId() == raceId) { - markCircle1.setCenterX(x); - markCircle1.setCenterY(y); - connectingLine.setStartX(markCircle1.getCenterX()); - connectingLine.setStartY(markCircle1.getCenterY()); + if (Math.abs(markCircle1.getCenterX() - x) > 5 || Math.abs(markCircle1.getCenterY() - y) > 5) { + markCircle1.setCenterX(x); + markCircle1.setCenterY(y); + connectingLine.setStartX(markCircle1.getCenterX()); + connectingLine.setStartY(markCircle1.getCenterY()); + } } else if (marks.get(1).getId() == raceId) { - markCircle2.setCenterX(x); - markCircle2.setCenterY(y); - connectingLine.setEndX(markCircle2.getCenterX()); - connectingLine.setEndY(markCircle2.getCenterY()); + if (Math.abs(markCircle2.getCenterX() - x) > 5 || Math.abs(markCircle2.getCenterY() - y) > 5) { + markCircle2.setCenterX(x); + markCircle2.setCenterY(y); + connectingLine.setEndX(markCircle2.getCenterX()); + connectingLine.setEndY(markCircle2.getCenterY()); + } } } } diff --git a/src/main/java/seng302/models/Wake.java b/src/main/java/seng302/fxObjects/Wake.java similarity index 97% rename from src/main/java/seng302/models/Wake.java rename to src/main/java/seng302/fxObjects/Wake.java index 886dfba8..706d1b1d 100644 --- a/src/main/java/seng302/models/Wake.java +++ b/src/main/java/seng302/fxObjects/Wake.java @@ -1,4 +1,4 @@ -package seng302.models; +package seng302.fxObjects; import javafx.scene.CacheHint; import javafx.scene.Group; @@ -14,7 +14,7 @@ import javafx.scene.transform.Rotate; class Wake extends Group { //The number of wakes - private int numWakes = 8; + private int numWakes = 6; //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. @@ -83,7 +83,7 @@ class Wake extends Group { for (Arc arc : arcs) { arc.setRadiusX(rad); arc.setRadiusY(rad); - rad += (20 / numWakes) + (velocity / 2); + rad += (12 / numWakes) + (velocity / 2); } } diff --git a/src/main/java/seng302/models/Yacht.java b/src/main/java/seng302/models/Yacht.java index 8ae5d76c..300c5a1d 100644 --- a/src/main/java/seng302/models/Yacht.java +++ b/src/main/java/seng302/models/Yacht.java @@ -1,9 +1,17 @@ package seng302.models; +import javafx.beans.InvalidationListener; +import javafx.beans.property.*; +import javafx.beans.value.ChangeListener; +import javafx.beans.value.ObservableValue; +import javafx.fxml.Initializable; import javafx.scene.paint.Color; import java.text.DateFormat; import java.text.SimpleDateFormat; +import java.time.Year; +import java.util.ArrayList; +import java.util.List; /** * Yacht class for the racing boat. @@ -14,7 +22,237 @@ import java.text.SimpleDateFormat; public class Yacht { // Used in boat group private Color colour; - private double velocity; + + private DoubleProperty velocityProperty = new DoubleProperty() { + + private ObservableValue boundValue; + private List changeListeners = new ArrayList<>(); + private List invalidationListeners = new ArrayList<>(); + private double velocity; + + @Override + public void bind(ObservableValue observable) { + boundValue = observable; + } + + @Override + public void unbind() { + boundValue = null; + } + + @Override + public boolean isBound() { + if (boundValue == null) { + return false; + } else { + return true; + } + } + + @Override + public Object getBean() { + return Yacht.this; + } + + @Override + public String getName() { + return "velocity property of " + boatName; + } + + @Override + public double get() { + return velocity; + } + + @Override + public void addListener(ChangeListener listener) { + changeListeners.add(listener); + } + + @Override + public void removeListener(ChangeListener listener) { + changeListeners.remove(listener); + } + + @Override + public void addListener(InvalidationListener listener) { + invalidationListeners.add(listener); + } + + @Override + public void removeListener(InvalidationListener listener) { + invalidationListeners.remove(listener); + } + + @Override + public void set (double newVelocity) { + double oldVelocity = velocity; + velocity = newVelocity; + if (newVelocity >= 0) + for (ChangeListener cl : changeListeners) { + cl.changed(this, oldVelocity, newVelocity); + } + else + for (InvalidationListener il : invalidationListeners) { + il.invalidated(this); + } + if (isBound()) + boundValue.notify(); + } + }; + private LongProperty timeAtNextProperty = new LongProperty() { + + private ObservableValue boundValue; + private List changeListeners = new ArrayList<>(); + private List invalidationListeners = new ArrayList<>(); + private long estimate; + + @Override + public void bind(ObservableValue observable) { + boundValue = observable; + } + + @Override + public void unbind() { + boundValue = null; + } + + @Override + public boolean isBound() { + if (boundValue == null) { + return false; + } else { + return true; + } + } + + @Override + public Object getBean() { + return Yacht.this; + } + + @Override + public String getName() { + return "estimated time to next mark property of " + boatName; + } + + @Override + public long get() { + return estimate; + } + + @Override + public void addListener(ChangeListener listener) { + changeListeners.add(listener); + } + + @Override + public void removeListener(ChangeListener listener) { + changeListeners.remove(listener); + } + + @Override + public void addListener(InvalidationListener listener) { + invalidationListeners.add(listener); + } + + @Override + public void removeListener(InvalidationListener listener) { + invalidationListeners.remove(listener); + } + + @Override + public void set (long newEstimate) { + long oldEstimate = estimate; + estimate = newEstimate; + if (newEstimate >= 0) + for (ChangeListener cl : changeListeners) { + cl.changed(this, oldEstimate, newEstimate); + } + else + for (InvalidationListener il : invalidationListeners) { + il.invalidated(this); + } + if (isBound()) + boundValue.notify(); + } + }; + private LongProperty markRoundingTimeProperty = new LongProperty() { + private ObservableValue boundValue; + private List changeListeners = new ArrayList<>(); + private List invalidationListeners = new ArrayList<>(); + private long roundingTime; + + @Override + public void bind(ObservableValue observable) { + boundValue = observable; + } + + @Override + public void unbind() { + boundValue = null; + } + + @Override + public boolean isBound() { + if (boundValue == null) { + return false; + } else { + return true; + } + } + + @Override + public Object getBean() { + return Yacht.this; + } + + @Override + public String getName() { + return "time from last mark property of " + boatName; + } + + @Override + public long get() { + return roundingTime; + } + + @Override + public void addListener(ChangeListener listener) { + changeListeners.add(listener); + } + + @Override + public void removeListener(ChangeListener listener) { + changeListeners.remove(listener); + } + + @Override + public void addListener(InvalidationListener listener) { + invalidationListeners.add(listener); + } + + @Override + public void removeListener(InvalidationListener listener) { + invalidationListeners.remove(listener); + } + + @Override + public void set (long newTime) { + long oldTime = newTime; + roundingTime = newTime; + if (newTime >= 0) + for (ChangeListener cl : changeListeners) { + cl.changed(this, oldTime, newTime); + } + else + for (InvalidationListener il : invalidationListeners) { + il.invalidated(this); + } + if (isBound()) + boundValue.notify(); + } + }; private String boatType; private Integer sourceID; @@ -27,11 +265,8 @@ public class Yacht { private Integer legNumber; private Integer penaltiesAwarded; private Integer penaltiesServed; - private Long estimateTimeAtNextMark; private Long estimateTimeAtFinish; private String position; - // Mark rounding - private Long markRoundingTime; /** * Used in EventTest and RaceTest. @@ -51,7 +286,7 @@ public class Yacht { */ public Yacht(String boatName, double boatVelocity, String shortName, int id) { this.boatName = boatName; - this.velocity = boatVelocity; + this.velocityProperty.set(boatVelocity); this.shortName = shortName; this.sourceID = id; } @@ -116,14 +351,8 @@ public class Yacht { this.penaltiesServed = penaltiesServed; } - public Long getEstimateTimeAtNextMark() { -// DateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss"); -// return format.format(estimateTimeAtNextMark); - return estimateTimeAtNextMark; - } - public void setEstimateTimeAtNextMark(Long estimateTimeAtNextMark) { - this.estimateTimeAtNextMark = estimateTimeAtNextMark; + timeAtNextProperty.set(estimateTimeAtNextMark); } public String getEstimateTimeAtFinish() { @@ -151,24 +380,29 @@ public class Yacht { this.colour = colour; } - public Double getVelocity() { - return velocity; - } - public void setVelocity(double velocity) { - this.velocity = velocity; + velocityProperty.set(velocity); } - public Long getMarkRoundingTime() { - return markRoundingTime; - } public void setMarkRoundingTime(Long markRoundingTime) { - this.markRoundingTime = markRoundingTime; + markRoundingTimeProperty.set(markRoundingTime); } @Override public String toString() { return boatName; } + + public ReadOnlyDoubleProperty getReadOnlyVelocityProperty () { + return velocityProperty; + } + + public ReadOnlyLongProperty getReadOnlyNextMarkProperty() { + return timeAtNextProperty; + } + + public ReadOnlyLongProperty getReadOnlyMarkRoundingProperty() { + return markRoundingTimeProperty; + } } diff --git a/src/main/java/seng302/models/stream/StreamParser.java b/src/main/java/seng302/models/stream/StreamParser.java index f800379c..9e8c5387 100644 --- a/src/main/java/seng302/models/stream/StreamParser.java +++ b/src/main/java/seng302/models/stream/StreamParser.java @@ -149,7 +149,7 @@ public class StreamParser extends Thread{ } } catch (NullPointerException e){ - System.out.println("Error parsing packet"); + System.out.println("Error parsing packet of type " + packet.getType()); } } From d22d758757edc8989fceef27afc5cf39afef8164 Mon Sep 17 00:00:00 2001 From: Calum Date: Wed, 24 May 2017 03:23:02 +1200 Subject: [PATCH 02/16] Fix issues caused by not updating the time since last mark value frequently. BoatAnnotations now has an update() function that must be called somewhat regularly. --- .../seng302/controllers/CanvasController.java | 1 - .../seng302/fxObjects/BoatAnnotations.java | 64 ++++++++----------- .../java/seng302/fxObjects/BoatGroup.java | 32 +++++----- src/main/java/seng302/fxObjects/Wake.java | 4 +- 4 files changed, 43 insertions(+), 58 deletions(-) diff --git a/src/main/java/seng302/controllers/CanvasController.java b/src/main/java/seng302/controllers/CanvasController.java index 12e29efa..fbd93c8a 100644 --- a/src/main/java/seng302/controllers/CanvasController.java +++ b/src/main/java/seng302/controllers/CanvasController.java @@ -15,7 +15,6 @@ import javafx.scene.canvas.GraphicsContext; import javafx.scene.layout.AnchorPane; import javafx.scene.paint.Color; import javafx.scene.text.Font; -import seng302.fxObjects.AnnotationsThingThatNeedsABetterName; import seng302.fxObjects.BoatGroup; import seng302.models.Colors; import seng302.models.Yacht; diff --git a/src/main/java/seng302/fxObjects/BoatAnnotations.java b/src/main/java/seng302/fxObjects/BoatAnnotations.java index d03d9e47..c43a13d9 100644 --- a/src/main/java/seng302/fxObjects/BoatAnnotations.java +++ b/src/main/java/seng302/fxObjects/BoatAnnotations.java @@ -2,9 +2,7 @@ package seng302.fxObjects; import javafx.scene.CacheHint; import javafx.scene.Group; -import javafx.scene.Node; import javafx.scene.paint.Color; -import javafx.scene.shape.Polygon; import javafx.scene.shape.Rectangle; import javafx.scene.text.Text; import seng302.models.Yacht; @@ -12,8 +10,6 @@ import seng302.models.stream.StreamParser; import java.text.DateFormat; import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.List; /** * Created by cir27 on 23/05/17. @@ -29,28 +25,26 @@ public class BoatAnnotations extends Group{ private static final double LEGTIME_X_OFFSET = 18d; private static final double LEGTIME_Y_OFFSET = 7d; -// private Rectangle background = new Rectangle(); + private Rectangle background = new Rectangle(); private Text teamNameObject; private Text velocityObject; private Text estTimeToNextMarkObject; private Text legTimeObject; - private List kids; - - private boolean visible = true; + private Long lastMarkTime; BoatAnnotations (Yacht boat, Color theme) { super.setCache(true); -// background.setX(15d); -// background.setY(-32d); -// background.setWidth(150); -// background.setHeight(55); -// background.setArcHeight(10); -// background.setArcWidth(10); -// background.setFill(new Color(1, 1, 1, 0.75)); -// background.setStroke(theme); -// background.setStrokeWidth(2); -// background.setCache(true); -// background.setCacheHint(CacheHint.SPEED); + background.setX(15d); + background.setY(-32d); + background.setWidth(150); + background.setHeight(55); + background.setArcHeight(10); + background.setArcWidth(10); + background.setFill(new Color(1, 1, 1, 0.25)); + background.setStroke(theme); + background.setStrokeWidth(2); + background.setCache(true); + background.setCacheHint(CacheHint.SPEED); teamNameObject = getTextObject(boat.getShortName(), theme); teamNameObject.relocate(TEAMNAME_X_OFFSET, TEAMNAME_Y_OFFSET); @@ -81,23 +75,13 @@ public class BoatAnnotations extends Group{ legTimeObject = getTextObject("Last mark: -", theme); legTimeObject.relocate(LEGTIME_X_OFFSET, LEGTIME_Y_OFFSET); boat.getReadOnlyMarkRoundingProperty().addListener((obs, oldTime, newTime) -> { - DateFormat format = new SimpleDateFormat("mm:ss"); - String elapsedTime = format - .format(StreamParser.getCurrentTimeLong() - newTime.longValue()); - legTimeObject.setText("Last mark: " + elapsedTime); + lastMarkTime = newTime.longValue(); }); boat.getReadOnlyMarkRoundingProperty().addListener(obs -> legTimeObject.setText("Last mark: - ") ); - kids = new ArrayList<>(); -// kids.add(background); - kids.add(velocityObject); - kids.add(teamNameObject); - kids.add(estTimeToNextMarkObject); - kids.add(legTimeObject); - -// super.getChildren().addAll(background, teamNameObject, velocityObject, estTimeToNextMarkObject, legTimeObject); + super.getChildren().addAll(background, teamNameObject, velocityObject, estTimeToNextMarkObject, legTimeObject); } /** @@ -110,7 +94,7 @@ public class BoatAnnotations extends Group{ private Text getTextObject(String defaultText, Color fill) { Text text = new Text(defaultText); text.setFill(fill); -// text.setCacheHint(CacheHint.SPEED); + text.setCacheHint(CacheHint.SPEED); text.setCache(true); return text; } @@ -131,12 +115,14 @@ public class BoatAnnotations extends Group{ legTimeObject.setVisible(visible); } - public void toggleVisible() { - visible = !visible; - this.setVisible(visible); - } - - public List getkiddies () { - return kids; + public void update () { + if (lastMarkTime != null) { + DateFormat format = new SimpleDateFormat("mm:ss"); + String elapsedTime = format + .format(StreamParser.getCurrentTimeLong() - lastMarkTime); + legTimeObject.setText("Last mark: " + elapsedTime); + }else { + legTimeObject.setText("Last mark: - "); + } } } diff --git a/src/main/java/seng302/fxObjects/BoatGroup.java b/src/main/java/seng302/fxObjects/BoatGroup.java index 2d659e84..a7b3535a 100644 --- a/src/main/java/seng302/fxObjects/BoatGroup.java +++ b/src/main/java/seng302/fxObjects/BoatGroup.java @@ -154,8 +154,7 @@ public class BoatGroup extends Group { boatAnnotations = new BoatAnnotations(boat, color); wake = new Wake(0, -BOAT_HEIGHT); - super.getChildren().addAll(boatPoly); - super.getChildren().addAll(boatAnnotations.getkiddies()); + super.getChildren().addAll(boatPoly, boatAnnotations); } /** @@ -180,12 +179,12 @@ public class BoatGroup extends Group { private void moveGroupBy(double dx, double dy) { boatPoly.setLayoutX(boatPoly.getLayoutX() + dx); boatPoly.setLayoutY(boatPoly.getLayoutY() + dy); -// boatAnnotations.setLayoutX(boatAnnotations.getLayoutX() + dx); -// boatAnnotations.setLayoutY(boatAnnotations.getLayoutY() + dy); - for (Node node : boatAnnotations.getkiddies()) { - node.setLayoutX(node.getLayoutX() + dx); - node.setLayoutY(node.getLayoutY() + dy); - } + boatAnnotations.setLayoutX(boatAnnotations.getLayoutX() + dx); + boatAnnotations.setLayoutY(boatAnnotations.getLayoutY() + dy); +// for (Node node : boatAnnotations.getkiddies()) { +// node.setLayoutX(node.getLayoutX() + dx); +// node.setLayoutY(node.getLayoutY() + dy); +// } wake.setLayoutX(wake.getLayoutX() + dx); wake.setLayoutY(wake.getLayoutY() + dy); } @@ -201,14 +200,14 @@ public class BoatGroup extends Group { rotateTo(rotation); boatPoly.setLayoutX(x); boatPoly.setLayoutY(y); -// boatAnnotations.setLayoutX(x); -// boatAnnotations.setLayoutY(y); - int i = 0; - for (Node n : boatAnnotations.getkiddies()) { - n.setLayoutX(x + 10 + i); - n.setLayoutY(y + 10 + i); - i += 10; - } + boatAnnotations.setLayoutX(x); + boatAnnotations.setLayoutY(y); +// int i = 0; +// for (Node n : boatAnnotations.getkiddies()) { +// n.setLayoutX(x + 10 + i); +// n.setLayoutY(y + 10 + i); +// i += 10; +// } wake.setLayoutX(x); wake.setLayoutY(y); wake.rotate(rotation); @@ -355,6 +354,7 @@ public class BoatGroup extends Group { lastTimeValid = timeValid; isStopped = false; lastRotation = rotation; + boatAnnotations.update(); } diff --git a/src/main/java/seng302/fxObjects/Wake.java b/src/main/java/seng302/fxObjects/Wake.java index 706d1b1d..dbeef2ee 100644 --- a/src/main/java/seng302/fxObjects/Wake.java +++ b/src/main/java/seng302/fxObjects/Wake.java @@ -14,7 +14,7 @@ import javafx.scene.transform.Rotate; class Wake extends Group { //The number of wakes - private int numWakes = 6; + 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. @@ -83,7 +83,7 @@ class Wake extends Group { for (Arc arc : arcs) { arc.setRadiusX(rad); arc.setRadiusY(rad); - rad += (12 / numWakes) + (velocity / 2); + rad += (10 / numWakes) + (velocity / 2); } } From c449da29168df15c52593b6fbee1a865072ba58a Mon Sep 17 00:00:00 2001 From: Zhi You Tan Date: Wed, 24 May 2017 14:24:14 +1200 Subject: [PATCH 03/16] [WIP] created finishScreenView.fxml, finishScreenViewController.java --- .../FinishScreenViewController.java | 88 +++++++++++++++++++ .../resources/views/FinishScreenView.fxml | 43 +++++++++ src/main/resources/views/FinishView.fxml | 55 ------------ 3 files changed, 131 insertions(+), 55 deletions(-) create mode 100644 src/main/java/seng302/controllers/FinishScreenViewController.java create mode 100644 src/main/resources/views/FinishScreenView.fxml delete mode 100644 src/main/resources/views/FinishView.fxml diff --git a/src/main/java/seng302/controllers/FinishScreenViewController.java b/src/main/java/seng302/controllers/FinishScreenViewController.java new file mode 100644 index 00000000..a4fde184 --- /dev/null +++ b/src/main/java/seng302/controllers/FinishScreenViewController.java @@ -0,0 +1,88 @@ +package seng302.controllers; + +import java.io.IOException; +import java.net.URL; +import java.util.ResourceBundle; +import java.util.Timer; +import java.util.TimerTask; +import javafx.application.Platform; +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; +import javafx.scene.control.TableView; +import javafx.scene.control.cell.PropertyValueFactory; +import javafx.scene.layout.AnchorPane; +import javafx.scene.layout.GridPane; +import javafx.scene.layout.Pane; +import javafx.scene.paint.Color; +import seng302.models.Yacht; +import seng302.models.stream.StreamParser; + +public class FinishScreenViewController implements Initializable { + @FXML + private GridPane finishScreenGridPane; + @FXML + private TableView finishOrderTable; + @FXML + private TableColumn posCol; + @FXML + private TableColumn boatNameCol; + @FXML + private TableColumn shortNameCol; + @FXML + private TableColumn countryCol; + + @Override + public void initialize(URL location, ResourceBundle resources) { + finishScreenGridPane.getStylesheets().add(getClass().getResource("/css/master.css").toString()); + finishOrderTable.getStylesheets().add(getClass().getResource("/css/master.css").toString()); + + // set up data for table + ObservableList data = FXCollections.observableArrayList(); + finishOrderTable.setItems(data); + + // setting table col data + posCol.setCellValueFactory( + new PropertyValueFactory<>("position") + ); + boatNameCol.setCellValueFactory( + new PropertyValueFactory<>("boatName") + ); + shortNameCol.setCellValueFactory( + new PropertyValueFactory<>("shortName") + ); + countryCol.setCellValueFactory( + new PropertyValueFactory<>("country") + ); + + // add data to table + data.addAll(StreamParser.getBoatsPos().values()); + finishOrderTable.refresh(); + } + + private void setContentPane(String jfxUrl){ + try{ + // get the main controller anchor pane (FinishView -> RaceView -> MainView) + AnchorPane contentPane = (AnchorPane) finishScreenGridPane.getParent().getParent(); + contentPane.getChildren().removeAll(); + contentPane.getChildren().clear(); + contentPane.getStylesheets().add(getClass().getResource("/css/master.css").toString()); + contentPane.getChildren().addAll((Pane) FXMLLoader.load(getClass().getResource(jfxUrl))); + } + catch(javafx.fxml.LoadException e){ + e.printStackTrace(); + } + catch(IOException e){ + e.printStackTrace(); + } + } + + public void switchToStartScreenView() { + setContentPane("/views/StartScreenView.fxml"); + } +} diff --git a/src/main/resources/views/FinishScreenView.fxml b/src/main/resources/views/FinishScreenView.fxml new file mode 100644 index 00000000..f12ccc25 --- /dev/null +++ b/src/main/resources/views/FinishScreenView.fxml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +