mirror of
https://github.com/michaelrausch/Party-Parrots-At-Sea.git
synced 2026-05-09 06:18:44 +00:00
Started to implement the group over the canvas in the code. Removed basic boat redrawing and timeline and replaced with boats being placed into a group and given coordinates.
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
package seng302.controllers;
|
||||
|
||||
import javafx.animation.*;
|
||||
import javafx.beans.property.SimpleDoubleProperty;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.Group;
|
||||
import javafx.scene.canvas.Canvas;
|
||||
import javafx.scene.canvas.GraphicsContext;
|
||||
import javafx.scene.layout.AnchorPane;
|
||||
@@ -14,6 +16,7 @@ import seng302.models.mark.Mark;
|
||||
import seng302.models.mark.MarkType;
|
||||
import seng302.models.mark.SingleMark;
|
||||
|
||||
import java.sql.Time;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
@@ -27,6 +30,7 @@ public class CanvasController {
|
||||
|
||||
private RaceViewController raceViewController;
|
||||
private ResizableCanvas canvas;
|
||||
private Group group;
|
||||
private GraphicsContext gc;
|
||||
|
||||
private final double ORIGIN_LAT = 32.321504;
|
||||
@@ -38,30 +42,51 @@ public class CanvasController {
|
||||
}
|
||||
|
||||
public void initialize() {
|
||||
raceViewController = new RaceViewController();
|
||||
canvas = new ResizableCanvas();
|
||||
group = new Group();
|
||||
|
||||
canvasPane.getChildren().add(canvas);
|
||||
canvasPane.getChildren().add(group);
|
||||
// Bind canvas size to stack pane size.
|
||||
canvas.widthProperty().bind(canvasPane.widthProperty());
|
||||
canvas.heightProperty().bind(canvasPane.heightProperty());
|
||||
canvas.widthProperty().bind(new SimpleDoubleProperty(1000));
|
||||
canvas.heightProperty().bind(new SimpleDoubleProperty(1000));
|
||||
group.minWidth(1000);
|
||||
group.minHeight(1000);
|
||||
// canvas.widthProperty().bind(canvasPane.widthProperty());
|
||||
// canvas.heightProperty().bind(canvasPane.heightProperty());
|
||||
// group.minWidth(canvas.getWidth());
|
||||
// group.minHeight(canvas.getHeight());
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void setUpBoats(){
|
||||
|
||||
gc = canvas.getGraphicsContext2D();
|
||||
|
||||
|
||||
gc.save();
|
||||
gc.setFill(Color.SKYBLUE);
|
||||
gc.fillRect(0,0, 1000,1000);
|
||||
gc.restore();
|
||||
drawBoats();
|
||||
drawCourse();
|
||||
drawFps(12);
|
||||
// overriding the handle so that it can clean canvas and redraw boats and course marks
|
||||
AnimationTimer timer = new AnimationTimer() {
|
||||
private long lastUpdate = 0;
|
||||
private long lastFpsUpdate = 0;
|
||||
private int lastFpsCount = 0;
|
||||
private int fpsCount = 0;
|
||||
boolean done = true;
|
||||
|
||||
@Override
|
||||
public void handle(long now) {
|
||||
if (true){ //if statement for limiting refresh rate if needed
|
||||
gc.clearRect(0, 0, canvas.getWidth(),canvas.getHeight());
|
||||
gc.setFill(Color.SKYBLUE);
|
||||
gc.fillRect(0,0,canvas.getWidth(),canvas.getHeight());
|
||||
drawCourse();
|
||||
drawBoats();
|
||||
drawFps(lastFpsCount);
|
||||
// gc.clearRect(0, 0, canvas.getWidth(),canvas.getHeight());
|
||||
// gc.setFill(Color.SKYBLUE);
|
||||
// gc.fillRect(0,0,canvas.getWidth(),canvas.getHeight());
|
||||
|
||||
|
||||
// If race has started, draw the boats and play the timeline
|
||||
if (raceViewController.getRace().getRaceTime() > 1){
|
||||
@@ -129,14 +154,26 @@ public class CanvasController {
|
||||
* Draws all the boats.
|
||||
*/
|
||||
private void drawBoats() {
|
||||
Map<Boat, TimelineInfo> timelineInfos = raceViewController.getTimelineInfos();
|
||||
for (Boat boat : timelineInfos.keySet()) {
|
||||
TimelineInfo timelineInfo = timelineInfos.get(boat);
|
||||
// Map<Boat, TimelineInfo> timelineInfos = raceViewController.getTimelineInfos();
|
||||
ArrayList<Boat> boats = raceViewController.getStartingBoats();
|
||||
Double startingY = (ORIGIN_LAT - raceViewController.getRace().getCourse().get(0).getLatitude()) * SCALE;
|
||||
Double startingX = (ORIGIN_LON - raceViewController.getRace().getCourse().get(0).getLongitude()) * SCALE;
|
||||
|
||||
boat.setLocation(timelineInfo.getY().doubleValue(), timelineInfo.getX().doubleValue());
|
||||
|
||||
drawBoat(boat.getLongitude(), boat.getLatitude(), boat.getColor(), boat.getShortName(), boat.getSpeedInKnots(), boat.getHeading());
|
||||
for (Boat boat : boats) {
|
||||
boat.moveBoatTo(startingX, startingY);
|
||||
group.getChildren().add(boat.getWake());
|
||||
group.getChildren().add(boat.getBoatObject());
|
||||
group.getChildren().add(boat.getTeamNameObject());
|
||||
group.getChildren().add(boat.getVelocityObject());
|
||||
// drawBoat(boat.getLongitude(), boat.getLatitude(), boat.getColor(), boat.getShortName(), boat.getSpeedInKnots(), boat.getHeading());
|
||||
}
|
||||
// for (Boat boat : timelineInfos.keySet()) {
|
||||
// TimelineInfo timelineInfo = timelineInfos.get(boat);
|
||||
//
|
||||
// boat.setLocation(timelineInfo.getY().doubleValue(), timelineInfo.getX().doubleValue());
|
||||
//
|
||||
// drawBoat(boat.getLongitude(), boat.getLatitude(), boat.getColor(), boat.getShortName(), boat.getSpeedInKnots(), boat.getHeading());
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -42,6 +42,7 @@ public class RaceViewController {
|
||||
@FXML
|
||||
private CanvasController includedCanvasController;
|
||||
|
||||
private ArrayList<Boat> startingBoats = new ArrayList<>();
|
||||
private boolean displayAnnotations;
|
||||
private boolean displayFps;
|
||||
private Timeline timerTimeline;
|
||||
@@ -50,24 +51,29 @@ public class RaceViewController {
|
||||
private Race race;
|
||||
|
||||
public void initialize() {
|
||||
includedCanvasController.setup(this);
|
||||
RaceController raceController = new RaceController();
|
||||
raceController.initializeRace();
|
||||
race = raceController.getRace();
|
||||
for (Boat boat : race.getBoats()) {
|
||||
startingBoats.add(boat);
|
||||
}
|
||||
// try{
|
||||
// initializeTimelines();
|
||||
// }
|
||||
// catch (Exception e){
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
|
||||
includedCanvasController.setup(this);
|
||||
includedCanvasController.setUpBoats();
|
||||
initializeTimer();
|
||||
initializeSettings();
|
||||
try{
|
||||
initializeTimelines();
|
||||
}
|
||||
catch (Exception e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
//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);
|
||||
|
||||
}
|
||||
|
||||
private void initializeSettings(){
|
||||
@@ -114,39 +120,39 @@ public class RaceViewController {
|
||||
*/
|
||||
private void initializeTimelines() {
|
||||
HashMap<Boat, List> 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<KeyFrame> keyFrames = new ArrayList<>();
|
||||
List<Event> 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));
|
||||
startingBoats.add(boat);
|
||||
// // x, y are the real time coordinates
|
||||
// DoubleProperty x = new SimpleDoubleProperty();
|
||||
// DoubleProperty y = new SimpleDoubleProperty();
|
||||
//
|
||||
// List<KeyFrame> keyFrames = new ArrayList<>();
|
||||
// List<Event> 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();
|
||||
}
|
||||
@@ -277,4 +283,8 @@ public class RaceViewController {
|
||||
public Map<Boat, TimelineInfo> getTimelineInfos() {
|
||||
return timelineInfos;
|
||||
}
|
||||
|
||||
public ArrayList<Boat> getStartingBoats(){
|
||||
return startingBoats;
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,24 @@
|
||||
package seng302.models;
|
||||
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.scene.shape.Polygon;
|
||||
import javafx.scene.text.Text;
|
||||
import javafx.scene.transform.Rotate;
|
||||
import javafx.scene.transform.Translate;
|
||||
|
||||
/**
|
||||
* Represents a boat in the race.
|
||||
*/
|
||||
public class Boat {
|
||||
|
||||
private static final double TEAMNAME_X_OFFSET = 15d;
|
||||
private static final double TEAMNAME_Y_OFFSET = -20d;
|
||||
private static final double VELOCITY_X_OFFSET = 15d;
|
||||
private static final double VELOCITY_Y_OFFSET = -10d;
|
||||
private static final double VELOCITY_WAKE_RATIO = 2d; //Ratio for deciding how long the wake will be wrt velocity
|
||||
private static final double BOAT_HEIGHT = 15d;
|
||||
private static final double BOAT_WIDTH = 10d;
|
||||
|
||||
private String teamName; // The name of the team, this is also the name of the boat
|
||||
private double velocity; // In meters/second
|
||||
private double lat; // Boats position
|
||||
@@ -17,6 +29,12 @@ public class Boat {
|
||||
private double heading;
|
||||
private String shortName;
|
||||
|
||||
//Graphical
|
||||
private Polygon boatObject;
|
||||
private Polygon wake;
|
||||
private Text teamNameObject;
|
||||
private Text velocityObject;
|
||||
|
||||
public Boat(String teamName) {
|
||||
this.teamName = teamName;
|
||||
this.velocity = 10; // Default velocity
|
||||
@@ -39,6 +57,13 @@ public class Boat {
|
||||
this.distanceToNextMark = 0.0;
|
||||
this.color = Colors.getColor();
|
||||
this.shortName = shortName;
|
||||
this.boatObject = new Polygon();
|
||||
this.boatObject.getPoints().addAll(BOAT_WIDTH /2,0.0,
|
||||
BOAT_WIDTH, BOAT_HEIGHT,
|
||||
0.0, BOAT_HEIGHT);
|
||||
createWake();
|
||||
this.teamNameObject = new Text(shortName);
|
||||
this.velocityObject = new Text(Double.toString(boatVelocity) + "ms");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -117,6 +142,11 @@ public class Boat {
|
||||
}
|
||||
|
||||
public void setHeading(double heading){
|
||||
boatObject.getTransforms().clear();
|
||||
wake.getTransforms().clear();
|
||||
wake.getTransforms().add(new Translate(0, BOAT_HEIGHT));
|
||||
wake.getTransforms().add(new Rotate(heading, BOAT_WIDTH/2, -BOAT_HEIGHT));
|
||||
boatObject.getTransforms().add(new Rotate(heading, BOAT_WIDTH/2, 0));
|
||||
this.heading = heading;
|
||||
}
|
||||
|
||||
@@ -127,4 +157,76 @@ public class Boat {
|
||||
public String getShortName(){
|
||||
return this.shortName;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Moves the boat and its children annotations from its current coordinates by specified amounts.
|
||||
* @param x The amount to move the X coordinate by
|
||||
* @param y The amount to move the Y coordinate by
|
||||
*/
|
||||
void moveBoatBy(Double x, Double y) {
|
||||
boatObject.setLayoutX(boatObject.getLayoutX() + x);
|
||||
boatObject.setLayoutY(boatObject.getLayoutY() + y);
|
||||
boatObject.relocate(boatObject.getLayoutX(), boatObject.getLayoutY());
|
||||
|
||||
teamNameObject.setX(teamNameObject.getX() + x);
|
||||
teamNameObject.setY(teamNameObject.getY() + y);
|
||||
teamNameObject.relocate(teamNameObject.getX(), teamNameObject.getY());
|
||||
|
||||
velocityObject.setX(velocityObject.getX() + x);
|
||||
velocityObject.setY(velocityObject.getY() + y);
|
||||
velocityObject.relocate(velocityObject.getX(), velocityObject.getY());
|
||||
|
||||
|
||||
wake.setLayoutX(wake.getLayoutX() + x);
|
||||
wake.setLayoutY(wake.getLayoutY() + y);
|
||||
wake.relocate(wake.getLayoutX(), wake.getLayoutY());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 moveBoatTo(Double x, Double y) {
|
||||
boatObject.setLayoutX(x);
|
||||
boatObject.setLayoutY(y);
|
||||
boatObject.relocate(boatObject.getLayoutX(), boatObject.getLayoutY());
|
||||
|
||||
teamNameObject.setX(x + TEAMNAME_X_OFFSET);
|
||||
teamNameObject.setY(y + TEAMNAME_Y_OFFSET);
|
||||
teamNameObject.relocate(teamNameObject.getX(), teamNameObject.getY());
|
||||
|
||||
velocityObject.setX(x + VELOCITY_X_OFFSET);
|
||||
velocityObject.setY(y + VELOCITY_Y_OFFSET);
|
||||
velocityObject.relocate(velocityObject.getX(), velocityObject.getY());
|
||||
|
||||
wake.setLayoutX(x);
|
||||
wake.setLayoutY(y);
|
||||
wake.relocate(wake.getLayoutX(), wake.getLayoutY());
|
||||
}
|
||||
|
||||
private void createWake(){
|
||||
wake = new Polygon();
|
||||
wake.setFill(Color.LIGHTSKYBLUE);
|
||||
wake.getPoints().addAll(5.0,0.0,
|
||||
10.0, velocity * VELOCITY_WAKE_RATIO,
|
||||
0.0, velocity * VELOCITY_WAKE_RATIO);
|
||||
}
|
||||
|
||||
public Polygon getWake() {
|
||||
return wake;
|
||||
}
|
||||
|
||||
public Polygon getBoatObject() {
|
||||
return boatObject;
|
||||
}
|
||||
|
||||
public Text getTeamNameObject() {
|
||||
return teamNameObject;
|
||||
}
|
||||
|
||||
public Text getVelocityObject() {
|
||||
return velocityObject;
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@ public class Event {
|
||||
private Mark mark1; // This mark
|
||||
private Mark mark2; // Next mark
|
||||
private int markPosInRace; // the position of the current mark in the race course
|
||||
|
||||
private double heading;
|
||||
private final double ORIGIN_LAT = 32.320504;
|
||||
private final double ORIGIN_LON = -64.857063;
|
||||
private final double SCALE = 16000;
|
||||
@@ -36,6 +36,8 @@ public class Event {
|
||||
this.mark1 = mark1;
|
||||
this.mark2 = mark2;
|
||||
this.markPosInRace = markPosInRace;
|
||||
this.heading = angleFromCoordinate(mark1, mark2);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -92,7 +94,7 @@ public class Event {
|
||||
if (this.isFinishingEvent) {
|
||||
return (this.getTimeString() + ", " + this.getBoat().getTeamName() + " finished the race");
|
||||
}
|
||||
System.out.println(this.getDistanceBetweenMarks());
|
||||
// System.out.println(this.getDistanceBetweenMarks());
|
||||
return (this.getTimeString() + ", " + this.getBoat().getTeamName() + " passed " + this.mark1.getName() + " going heading " + this.getBoatHeading() + "°");
|
||||
}
|
||||
|
||||
@@ -138,6 +140,30 @@ public class Event {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the angle between to angular co-ordinates on a sphere.
|
||||
*
|
||||
* @param geoPointOne first geographical location
|
||||
* @param geoPointTwo second geographical location
|
||||
* @return the angle from point one to point two
|
||||
*/
|
||||
private Double angleFromCoordinate(Mark geoPointOne, Mark geoPointTwo) {
|
||||
if (geoPointTwo == null)
|
||||
return null;
|
||||
|
||||
double x1 = geoPointOne.getLatitude();
|
||||
double y1 = -geoPointOne.getLongitude();
|
||||
double x2 = geoPointTwo.getLatitude();
|
||||
double y2 = -geoPointTwo.getLongitude();
|
||||
|
||||
return Math.toDegrees(Math.atan2(x2-x1, y2-y1));
|
||||
|
||||
}
|
||||
|
||||
public double getHeading() {
|
||||
return heading;
|
||||
}
|
||||
|
||||
public Mark getThisMark() {
|
||||
return this.mark1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user