From ee34e5028feebc5b8a7d9c373e1a66f6a1e3e31c Mon Sep 17 00:00:00 2001 From: Haoming Yin Date: Mon, 20 Mar 2017 17:23:33 +1300 Subject: [PATCH] Reformatted and refactored the canvas controller #fix #refactor #story[377] --- .../seng302/controllers/CanvasController.java | 150 ++++++++++------- src/main/java/seng302/models/OldApp.java | 4 +- src/main/java/seng302/models/Race.java | 158 ++---------------- 3 files changed, 109 insertions(+), 203 deletions(-) diff --git a/src/main/java/seng302/controllers/CanvasController.java b/src/main/java/seng302/controllers/CanvasController.java index 102a9833..898eb714 100644 --- a/src/main/java/seng302/controllers/CanvasController.java +++ b/src/main/java/seng302/controllers/CanvasController.java @@ -11,10 +11,14 @@ import javafx.scene.canvas.Canvas; import javafx.scene.canvas.GraphicsContext; import javafx.scene.paint.Color; import javafx.util.Duration; -import seng302.models.*; +import seng302.models.Boat; +import seng302.models.Event; +import seng302.models.Race; +import seng302.models.TimelineInfo; import seng302.models.mark.GateMark; import seng302.models.mark.Mark; import seng302.models.mark.MarkType; +import seng302.models.mark.SingleMark; import java.util.ArrayList; import java.util.HashMap; @@ -24,103 +28,129 @@ import static java.lang.Math.abs; /** * Created by ptg19 on 15/03/17. + * Modified by Haoming Yin (hyi25) on 20/3/2017. */ public class CanvasController { - @FXML private Canvas canvas; - Race race; - GraphicsContext gc; - HashMap timelineInfos; + private Race race; + private GraphicsContext gc; + private HashMap timelineInfos; + @FXML + private Canvas canvas; public void initialize() { gc = canvas.getGraphicsContext2D(); - gc.scale(5,5); + gc.scale(5, 5); RaceController raceController = new RaceController(); raceController.initializeRace(); race = raceController.getRace(); timelineInfos = new HashMap<>(); - HashMap boat_events = race.getEvents(); -// System.out.println(boat_events); - - // generating timelines - for (Boat boat : boat_events.keySet()) { - DoubleProperty x = new SimpleDoubleProperty(); - DoubleProperty y = new SimpleDoubleProperty(); - List keyFrames = new ArrayList<>(); - List events = boat_events.get(boat); - for (Event event: events){ - keyFrames.add( -// new KeyFrame(Duration.seconds(event.getDistanceBetweenMarks()/event.getBoat().getVelocity()), - new KeyFrame(Duration.seconds(event.getTime()/60/60/5), - new KeyValue(x, event.getMark().getLatitude()), - new KeyValue(y, event.getMark().getLongitude()) - ) - ); -// drawBoat(gc, event.getMark().getLatitude(), event.getMark().getLongitude(), Colors.getColor()); - System.out.println(event.getMark().getName()); - } - timelineInfos.put(boat, new TimelineInfo(new Timeline(keyFrames.toArray(new KeyFrame[keyFrames.size()])), x, y)); - } - + // overriding the handle so that it can clean canvas and redraw boats and course marks AnimationTimer timer = new AnimationTimer() { @Override public void handle(long now) { - gc.clearRect(0,0,760,360); + gc.clearRect(0, 0, 760, 360); drawCourse(); drawBoats(); } }; + + generateTimeline(); + + // starts the timer and reads events from each boat's time line timer.start(); - for (TimelineInfo timelineInfo: timelineInfos.values()){ + for (TimelineInfo timelineInfo : timelineInfos.values()) { Timeline timeline = timelineInfo.getTimeline(); timeline.play(); } } - private void drawBoats(){ - for (Boat boat: timelineInfos.keySet()){ + /** + * Generates time line for each boat, and stores time time into timelineInfos hash map + */ + private void generateTimeline() { + HashMap boat_events = race.getEvents(); + for (Boat boat : boat_events.keySet()) { + // 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) { + keyFrames.add( + new KeyFrame(Duration.seconds(event.getTime() / 60 / 60 / 5), + new KeyValue(x, event.getMark().getLatitude()), + new KeyValue(y, event.getMark().getLongitude()) + ) + ); + } + + // uses the lists generated above to create a Timeline for the boat. + timelineInfos.put(boat, new TimelineInfo(new Timeline(keyFrames.toArray(new KeyFrame[keyFrames.size()])), x, y)); + } + } + + /** + * Draws all the boats. + */ + private void drawBoats() { + for (Boat boat : timelineInfos.keySet()) { TimelineInfo timelineInfo = timelineInfos.get(boat); drawBoat(timelineInfo.getX().doubleValue(), timelineInfo.getY().doubleValue(), boat.getColor()); } } + /** + * Draws a boat with given (x, y) position in the given color + * + * @param x + * @param y + * @param color + */ private void drawBoat(double x, double y, Color color) { - x = abs(x - 32.313291) * 1000; // to prevent negative longtitude + x = abs(x - 32.313291) * 1000; // to prevent negative longitude y = abs(y + 64.887057) * 1000; // to prevent negative latitude -// y = abs(y); int diameter = 2; gc.setFill(color); gc.fillOval(x, y, diameter, diameter); } - private void drawCourse(){ - for (Mark mark: race.getCourse()){ - gc.setFill(Color.BLACK); - - if (mark.getMarkType() == MarkType.SINGLE_MARK){ - double x = abs(mark.getLatitude() - 32.313291) * 1000; // to prevent negative longtitude - double y = abs(mark.getLongitude() + 64.887057) * 1000; // to prevent negative latitude - - gc.fillOval(x, y, 2, 2); - } - - else if (mark.getMarkType() == MarkType.GATE_MARK){ - double x; - double y; - GateMark gateMark = (GateMark) mark; - Mark mark1 = gateMark.getSingleMark1(); - Mark mark2 = gateMark.getSingleMark1(); - - x = abs(mark1.getLatitude() - 32.313291) * 1000; // to prevent negative longtitude - y = abs(mark1.getLongitude() + 64.887057) * 1000; // to prevent negative latitude - gc.fillOval(x, y, 2, 2); - - x = abs(mark2.getLatitude() - 32.313291) * 1000; // to prevent negative longtitude - y = abs(mark2.getLongitude() + 64.887057) * 1000; // to prevent negative latitude - gc.fillOval(x, y, 2, 2); + /** + * Draws the course. + */ + private void drawCourse() { + for (Mark mark : race.getCourse()) { + if (mark.getMarkType() == MarkType.SINGLE_MARK) { + drawSingleMark((SingleMark) mark); + } else if (mark.getMarkType() == MarkType.GATE_MARK) { + drawGateMark((GateMark) mark); } } } + + /** + * Draw a given mark on canvas + * + * @param singleMark + */ + private void drawSingleMark(SingleMark singleMark) { + double x = abs(singleMark.getLatitude() - 32.313291) * 1000; // to prevent negative longitude + double y = abs(singleMark.getLongitude() + 64.887057) * 1000; // to prevent negative latitude + gc.setFill(Color.BLACK); + gc.fillOval(x, y, 2, 2); + } + + /** + * Draw a gate mark which contains two single marks + * + * @param gateMark + */ + private void drawGateMark(GateMark gateMark) { + drawSingleMark(gateMark.getSingleMark1()); + drawSingleMark(gateMark.getSingleMark2()); + } } diff --git a/src/main/java/seng302/models/OldApp.java b/src/main/java/seng302/models/OldApp.java index 420b19ec..aed658be 100644 --- a/src/main/java/seng302/models/OldApp.java +++ b/src/main/java/seng302/models/OldApp.java @@ -81,7 +81,7 @@ public class OldApp { // If race was created if (race != null) { - race.displayStartingBoats(); + //race.displayStartingBoats(); System.out.println("\n\n"); System.out.println("######################"); @@ -96,7 +96,7 @@ public class OldApp { System.out.println("######################"); //race.showRaceMarkerResults(); - race.displayFinishingOrder(); + //race.displayFinishingOrder(); } else { System.out.println("There was an error creating the race. Exiting."); diff --git a/src/main/java/seng302/models/Race.java b/src/main/java/seng302/models/Race.java index 7695a17b..4fe443c2 100644 --- a/src/main/java/seng302/models/Race.java +++ b/src/main/java/seng302/models/Race.java @@ -1,46 +1,28 @@ package seng302.models; -import seng302.models.mark.*; +import seng302.models.mark.Mark; -import java.lang.reflect.Array; import java.util.*; /** -* Race class containing the boats and legs in the race -*/ + * 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 int numberOfBoats = 0; private long startTime = 0; private double timeScale = 1; /** - * Race class containing the boats and legs 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(); - - // create a priority queue with a custom Comparator to order events -// this.events = new PriorityQueue(new Comparator() { -// @Override -// public int compare(Event o1, Event o2) { -// Double time1 = o1.getTime(); -// Double time2 = o2.getTime(); -// -// // order event asc. by time. if tie appears, then order team -// // name alphabetically. -// if (time1 != time2) { -// return time1.compareTo(time2); -// } else { -// return o1.getBoat().getTeamName().compareTo(o2.getBoat().getTeamName()); -// } -// } -// }); + this.boats = new ArrayList<>(); + this.finishingOrder = new ArrayList<>(); + this.course = new ArrayList<>(); } /** @@ -50,7 +32,6 @@ public class Race { */ public void addBoat(Boat boat) { boats.add(boat); - numberOfBoats += 1; } /** @@ -76,14 +57,6 @@ public class Race { return this.finishingOrder.toArray(new Boat[this.finishingOrder.size()]); } - /** - * Returns the number of boats in the race - * - * @returns the number of boats in the race - */ - public int getNumberOfBoats() { - return numberOfBoats; - } /** * Returns a list of boats in the race @@ -95,38 +68,7 @@ public class Race { } /** - * Prints the order in which the boats finished the race - */ - public void displayFinishingOrder() { - int numberOfBoats = this.getNumberOfBoats(); - Boat[] boats = this.getFinishedBoats(); - - System.out.println("--- Finishing Order ---"); - - for (int i = 0; i < Array.getLength(boats); i++) { - System.out.println("#" + Integer.toString(i + 1) + " - " + boats[i].getTeamName()); - } - } - - /** - * Prints the list of boats competing in the race - */ - public void displayStartingBoats() { - int numberOfBoats = this.getNumberOfBoats(); - Boat[] boats = this.getBoats(); - - System.out.println("######################"); - System.out.println("# Competing Boats "); - System.out.println("######################"); - - for (int i = 0; i < numberOfBoats; i++) { - String velocityKnots = String.format("%1.2f", boats[i].getVelocity() * 1.943844492); - - System.out.println(boats[i].getTeamName() + " Velocity: " + velocityKnots + " Knots/s"); - } - } - /** - * Sets time scale + * Sets time scale * * @param timeScale */ @@ -138,107 +80,41 @@ public class Race { * Generate all events that will happen during the race. */ private void generateEvents() { - //calculate the time every boat passes each leg, and create an event for (Boat boat : this.boats) { double totalDistance = 0; int numberOfMarks = this.course.size(); - for(int i = 0; i < numberOfMarks; i++){ - Double time = (Double) (1000 * totalDistance / boat.getVelocity()); + for (int i = 0; i < numberOfMarks; i++) { + Double time = (1000 * totalDistance / boat.getVelocity()); // If there are singleMarks after this event - if (i < numberOfMarks-1) { + if (i < numberOfMarks - 1) { Event event = new Event(time, boat, course.get(i), course.get(i + 1)); try { events.get(boat).add(event); } catch (NullPointerException e) { - events.put(boat, new ArrayList(Arrays.asList(event))); + events.put(boat, new ArrayList<>(Arrays.asList(event))); } totalDistance += event.getDistanceBetweenMarks(); } - // There are no more marks after this event -// else{ -// Event event = new Event(time, boat, marks.get(i)); -// events.put(boat, new ArrayList(Arrays.asList(event))); -// } } } } - /** - * Calculates how far a boat has travelled in meters - * - * @param velocity the velocity of boat - * @return a float number of distance the boat has been travelled - */ - public float getDistanceTravelled(long velocity) { - long timeDiff = System.currentTimeMillis() - this.startTime; - long timeElapse = (long) (timeDiff / 1000 * this.timeScale); - return timeElapse * velocity; - } /** - * Iterate over events in the race and print the - * event string for each event - */ -// public void iterateEvents() { -// // iterates all events. ends when no event in events. -// -// while (!events.isEmpty()) { -// Event peekEvent = events.peek(); -// long currentTime = (long) ((System.currentTimeMillis() - this.startTime) * this.timeScale); -// -// if (currentTime > peekEvent.getTime()) { -// Event nextEvent = events.poll(); -// -// // Display a summary of the event -// System.out.println(nextEvent.getEventString()); -// -// // Display latitude and longitude -// if (!nextEvent.getIsFinishingEvent()){ -// System.out.println(nextEvent.getMark().getLatitude() + ", " + nextEvent.getNextMark().getLongitude()); -// } -// -// System.out.println(); -// -// // If event is a boat finishing the race -// if (nextEvent.getIsFinishingEvent()) { -// this.finishingOrder.add(nextEvent.getBoat()); -// } -// } -// -// // Wait for 100ms to throttle the while loop -// try { -// Thread.sleep(100); -// } catch (java.lang.InterruptedException e) { -// continue; -// } -// } -// } - - /** - * Start the race and print each marker with the order - * in which the boats passed that marker + * Starts a race and generates all events for the race. */ public void startRace() { // record start time. + this.startTime = System.currentTimeMillis(); generateEvents(); -// this.startTime = System.currentTimeMillis(); -// iterateEvents(); } -// -// /** -// * Add a singleMark to the race (in order) -// * @param singleMark, the singleMark to add -// */ -// public void addMark(SingleMark singleMark){ -// this.marks.add(singleMark); -// } - public void addCourse(List course){ + public void addCourse(List course) { this.course = course; }