diff --git a/racevisionGame/src/main/java/visualiser/Controllers/RaceController.java b/racevisionGame/src/main/java/visualiser/Controllers/RaceController.java index 35e20cb7..e864993d 100644 --- a/racevisionGame/src/main/java/visualiser/Controllers/RaceController.java +++ b/racevisionGame/src/main/java/visualiser/Controllers/RaceController.java @@ -178,35 +178,39 @@ public class RaceController extends Controller { private void initialiseView3D(VisualiserRaceEvent race) { viewSubjects = FXCollections.observableArrayList(); + // Import boat mesh URL asset = HostController.class.getClassLoader().getResource("assets/V1.2 Complete Boat.stl"); StlMeshImporter importer = new StlMeshImporter(); importer.read(asset); + // Configure camera angles and control view3D = new View3D(); view3D.setDistance(1050); view3D.setYaw(0); view3D.setPitch(60); + view3D.enableTracking(); + canvasBase.add(view3D, 0, 0); + // Set up projection from GPS to view RaceDataSource raceData = visualiserRace.getVisualiserRaceState().getRaceDataSource(); final GPSConverter gpsConverter = new GPSConverter(raceData, 450, 450); view3D.setItems(viewSubjects); - view3D.enableTracking(); - canvasBase.add(view3D, 0, 0); - + // Position and add each mark to view for(Mark mark: race.getVisualiserRaceState().getMarks()) { - Subject3D subject = new Subject3D(new Sphere(5)); + Subject3D subject = new Subject3D(new Sphere(2)); subject.setX(gpsConverter.convertGPS(mark.getPosition()).getX()); subject.setZ(gpsConverter.convertGPS(mark.getPosition()).getY()); viewSubjects.add(subject); } - + // Position and add each boat to view for(VisualiserBoat boat: race.getVisualiserRaceState().getBoats()) { MeshView mesh = new MeshView(importer.getImport()); Subject3D subject = new Subject3D(mesh); viewSubjects.add(subject); + // Track this boat's movement with the new subject AnimationTimer trackBoat = new AnimationTimer() { @Override public void handle(long now) { @@ -217,12 +221,15 @@ public class RaceController extends Controller { }; trackBoat.start(); } + // Fix initial bird's-eye position view3D.updatePivot(new Translate(250, 0, 210)); + // Bind zooming to scrolling view3D.setOnScroll(e -> { view3D.updateDistance(e.getDeltaY()); }); + // Bind zooming to keypress (Z/X default) racePane.addEventFilter(KeyEvent.KEY_PRESSED, e -> { ControlKey key = keyFactory.getKey(e.getCode().toString()); if(key != null) { diff --git a/racevisionGame/src/main/java/visualiser/layout/View3D.java b/racevisionGame/src/main/java/visualiser/layout/View3D.java index db5ee85b..27fe6086 100644 --- a/racevisionGame/src/main/java/visualiser/layout/View3D.java +++ b/racevisionGame/src/main/java/visualiser/layout/View3D.java @@ -128,6 +128,11 @@ public class View3D extends Pane { return camera; } + /** + * Provide the list of subjects to be automatically added or removed from the view as the list + * changes. + * @param items list managed by client + */ public void setItems(ObservableList items) { this.items = items; this.items.addListener((ListChangeListener) c -> { @@ -146,6 +151,9 @@ public class View3D extends Pane { }); } + /** + * Intercept mouse clicks on subjects in view. The applied listener cannot be removed. + */ public void enableTracking() { scene.setOnMousePressed(e -> { PickResult result = e.getPickResult(); @@ -155,6 +163,9 @@ public class View3D extends Pane { }); } + /** + * Stop camera from following the last selected subject + */ private void untrackSubject() { if(target != null) { target.getPosition().xProperty().removeListener(pivotX); @@ -164,6 +175,10 @@ public class View3D extends Pane { } } + /** + * Set camera to follow the selected subject + * @param subject to track + */ private void trackSubject(Subject3D subject) { untrackSubject(); target = subject; @@ -188,6 +203,10 @@ public class View3D extends Pane { this.farClip = farClip; } + /** + * Sets the coordinates of the camera pivot once. + * @param pivot source of coordinates + */ public void updatePivot(Translate pivot) { this.pivot.setX(pivot.getX()); this.pivot.setY(pivot.getY()); diff --git a/racevisionGame/src/main/java/visualiser/utils/GPSConverter.java b/racevisionGame/src/main/java/visualiser/utils/GPSConverter.java index 49ef7bcb..22dd937f 100644 --- a/racevisionGame/src/main/java/visualiser/utils/GPSConverter.java +++ b/racevisionGame/src/main/java/visualiser/utils/GPSConverter.java @@ -5,14 +5,15 @@ import shared.model.GPSCoordinate; import visualiser.model.GraphCoordinate; /** - * Created by fwy13 on 7/09/17. + * Converts GPS coordinates to view volume coordinates. Longitudes are equally spaced at all latitudes, + * which leads to inaccurate distance measurements close to the poles. This is acceptable as races are + * not likely to be set there. */ public class GPSConverter { private double longRight; private double longLeft; private double latBottom; private double latTop; - /** * Conversion factor from longitude to view units */ @@ -22,6 +23,12 @@ public class GPSConverter { */ private double latitudeFactor; + /** + * Set up projection with default view boundaries from RaceDataSource + * @param source for view boundaries + * @param longitudeFactor separation of a degree of longitude in view units + * @param latitudeFactor separation of a degree of latitude in view units + */ public GPSConverter(RaceDataSource source, double longitudeFactor, double latitudeFactor) { this.latTop = source.getMapTopLeft().getLatitude(); this.longLeft = source.getMapTopLeft().getLongitude();