From 56c4e8de651ade1aec763b812f060bac258b9b1e Mon Sep 17 00:00:00 2001 From: Eugene Maksymenko <maxigene@gmail.com> Date: Thu, 4 Aug 2022 22:34:28 +0300 Subject: [PATCH] Remove WorldWindow dependency from Camera. --- .../BasicPerformanceBenchmarkActivity.java | 24 +-- .../nasa/worldwindx/GeneralGlobeActivity.java | 7 +- .../OmnidirectionalSightlineActivity.java | 2 +- .../PlacemarksMilStd2525Activity.java | 2 +- .../PlacemarksSelectDragActivity.java | 2 +- .../main/assets/look_at_view_tutorial.html | 2 +- .../assets/navigator_events_tutorial.html | 5 +- .../assets/placemarks_picking_tutorial.html | 2 +- .../src/main/assets/placemarks_tutorial.html | 2 +- .../worldwindx/CameraControlFragment.java | 22 +- .../nasa/worldwindx/LookAtViewFragment.java | 2 +- .../worldwindx/NavigatorEventFragment.java | 7 +- .../OmnidirectionalSightlineFragment.java | 2 +- .../nasa/worldwindx/PlacemarksFragment.java | 2 +- .../worldwindx/PlacemarksPickingFragment.java | 2 +- .../worldwind/BasicWorldWindowController.java | 20 +- .../java/gov/nasa/worldwind/Navigator.java | 51 ++--- .../java/gov/nasa/worldwind/WorldWindow.java | 6 +- .../java/gov/nasa/worldwind/geom/Camera.java | 66 +++--- .../gov/nasa/worldwind/geom/FrustumTest.java | 190 +++++++++--------- 20 files changed, 214 insertions(+), 204 deletions(-) diff --git a/worldwind-examples/src/main/java/gov/nasa/worldwindx/BasicPerformanceBenchmarkActivity.java b/worldwind-examples/src/main/java/gov/nasa/worldwindx/BasicPerformanceBenchmarkActivity.java index 80c0a73ec..2a14281d9 100644 --- a/worldwind-examples/src/main/java/gov/nasa/worldwindx/BasicPerformanceBenchmarkActivity.java +++ b/worldwind-examples/src/main/java/gov/nasa/worldwindx/BasicPerformanceBenchmarkActivity.java @@ -67,9 +67,9 @@ public static class AnimateCameraCommand implements Runnable { public AnimateCameraCommand(WorldWindow wwd, Camera end, int steps) { this.wwd = wwd; - this.beginCamera = new Camera(wwd); - this.endCamera = new Camera(wwd); - this.curCamera = new Camera(wwd); + this.beginCamera = new Camera(); + this.endCamera = new Camera(); + this.curCamera = new Camera(); this.endCamera.set(end); this.steps = steps; @@ -117,7 +117,7 @@ public static SetCameraCommand obtain(WorldWindow wwd, Camera camera) { private SetCameraCommand set(WorldWindow wwd, Camera camera) { this.wwd = wwd; - this.camera = new Camera(wwd); + this.camera = new Camera(); this.camera.set(camera); return this; } @@ -240,12 +240,12 @@ protected void onStart() { exec.execute(new ClearFrameMetricsCommand(wwd)); // After a 1/2 second delay, fly to NASA Ames Research Center over 100 frames. - Camera cam = new Camera(this.getWorldWindow()).set(arc.latitude, arc.longitude, 10e3, WorldWind.ABSOLUTE, 0, 0, 0); + Camera cam = new Camera().set(arc.latitude, arc.longitude, 10e3, WorldWind.ABSOLUTE, 0, 0, 0); exec.execute(new AnimateCameraCommand(wwd, cam, 100)); // After a 1/2 second delay, rotate the camera to look at NASA Goddard Space Flight Center over 50 frames. double azimuth = arc.greatCircleAzimuth(gsfc); - cam = new Camera(this.getWorldWindow()).set(arc.latitude, arc.longitude, 10e3, WorldWind.ABSOLUTE, azimuth, 70, 0); + cam = new Camera().set(arc.latitude, arc.longitude, 10e3, WorldWind.ABSOLUTE, azimuth, 70, 0); exec.execute(new SleepCommand(500)); exec.execute(new AnimateCameraCommand(wwd, cam, 50)); @@ -253,27 +253,27 @@ protected void onStart() { Location midLoc = arc.interpolateAlongPath(gsfc, WorldWind.GREAT_CIRCLE, 0.5, new Location()); azimuth = midLoc.greatCircleAzimuth(gsfc); exec.execute(new SleepCommand(500)); - cam = new Camera(this.getWorldWindow()).set(midLoc.latitude, midLoc.longitude, 1000e3, WorldWind.ABSOLUTE, azimuth, 0, 0); + cam = new Camera().set(midLoc.latitude, midLoc.longitude, 1000e3, WorldWind.ABSOLUTE, azimuth, 0, 0); exec.execute(new AnimateCameraCommand(wwd, cam, 100)); - cam = new Camera(this.getWorldWindow()).set(gsfc.latitude, gsfc.longitude, 10e3, WorldWind.ABSOLUTE, azimuth, 70, 0); + cam = new Camera().set(gsfc.latitude, gsfc.longitude, 10e3, WorldWind.ABSOLUTE, azimuth, 70, 0); exec.execute(new AnimateCameraCommand(wwd, cam, 100)); // After a 1/2 second delay, rotate the camera to look at ESA Centre for Earth Observation over 50 frames. azimuth = gsfc.greatCircleAzimuth(esrin); - cam = new Camera(this.getWorldWindow()).set(gsfc.latitude, gsfc.longitude, 10e3, WorldWind.ABSOLUTE, azimuth, 90, 0); + cam = new Camera().set(gsfc.latitude, gsfc.longitude, 10e3, WorldWind.ABSOLUTE, azimuth, 90, 0); exec.execute(new SleepCommand(500)); exec.execute(new AnimateCameraCommand(wwd, cam, 50)); // After a 1/2 second delay, fly the camera to ESA Centre for Earth Observation over 200 frames. midLoc = gsfc.interpolateAlongPath(esrin, WorldWind.GREAT_CIRCLE, 0.5, new Location()); exec.execute(new SleepCommand(500)); - cam = new Camera(this.getWorldWindow()).set(midLoc.latitude, midLoc.longitude, 1000e3, WorldWind.ABSOLUTE, azimuth, 60, 0); + cam = new Camera().set(midLoc.latitude, midLoc.longitude, 1000e3, WorldWind.ABSOLUTE, azimuth, 60, 0); exec.execute(new AnimateCameraCommand(wwd, cam, 100)); - cam = new Camera(this.getWorldWindow()).set(esrin.latitude, esrin.longitude, 100e3, WorldWind.ABSOLUTE, azimuth, 30, 0); + cam = new Camera().set(esrin.latitude, esrin.longitude, 100e3, WorldWind.ABSOLUTE, azimuth, 30, 0); exec.execute(new AnimateCameraCommand(wwd, cam, 100)); // After a 1/2 second delay, back the camera out to look at ESA Centre for Earth Observation over 100 frames. - cam = new Camera(this.getWorldWindow()).set(esrin.latitude, esrin.longitude, 2000e3, WorldWind.ABSOLUTE, 0, 0, 0); + cam = new Camera().set(esrin.latitude, esrin.longitude, 2000e3, WorldWind.ABSOLUTE, 0, 0, 0); exec.execute(new SleepCommand(500)); exec.execute(new AnimateCameraCommand(wwd, cam, 100)); diff --git a/worldwind-examples/src/main/java/gov/nasa/worldwindx/GeneralGlobeActivity.java b/worldwind-examples/src/main/java/gov/nasa/worldwindx/GeneralGlobeActivity.java index fd6dbec27..8993f2150 100644 --- a/worldwind-examples/src/main/java/gov/nasa/worldwindx/GeneralGlobeActivity.java +++ b/worldwind-examples/src/main/java/gov/nasa/worldwindx/GeneralGlobeActivity.java @@ -16,10 +16,12 @@ import gov.nasa.worldwind.NavigatorEvent; import gov.nasa.worldwind.NavigatorListener; +import gov.nasa.worldwind.PickedObject; import gov.nasa.worldwind.WorldWind; import gov.nasa.worldwind.WorldWindow; import gov.nasa.worldwind.geom.Camera; import gov.nasa.worldwind.geom.LookAt; +import gov.nasa.worldwind.geom.Position; /** * Creates a general purpose globe view with touch navigation, a few layers, and a coordinates overlay. @@ -79,9 +81,12 @@ public void onNavigatorEvent(WorldWindow wwd, NavigatorEvent event) { // Update the status overlay views whenever the navigator stops moving, // and also it is moving but at an (arbitrary) maximum refresh rate of 20 Hz. if (eventAction == WorldWind.NAVIGATOR_STOPPED || elapsedTime > 50) { + // Pick terrain located behind the viewport center point + PickedObject terrainPickedObject = wwd.pick(wwd.getViewport().width / 2f, wwd.getViewport().height / 2f).terrainPickedObject(); + Position terrainPosition = terrainPickedObject != null ? terrainPickedObject.getTerrainPosition() : null; // Get the current camera state to apply to the overlays - event.getCamera().getAsLookAt(lookAt); + event.getCamera().getAsLookAt(wwd.getGlobe(), wwd.getVerticalExaggeration(), terrainPosition, lookAt); // Update the overlays updateOverlayContents(lookAt, event.getCamera()); diff --git a/worldwind-examples/src/main/java/gov/nasa/worldwindx/OmnidirectionalSightlineActivity.java b/worldwind-examples/src/main/java/gov/nasa/worldwindx/OmnidirectionalSightlineActivity.java index 6aa734ed2..14e17f018 100644 --- a/worldwind-examples/src/main/java/gov/nasa/worldwindx/OmnidirectionalSightlineActivity.java +++ b/worldwind-examples/src/main/java/gov/nasa/worldwindx/OmnidirectionalSightlineActivity.java @@ -89,7 +89,7 @@ protected void onCreate(Bundle savedInstanceState) { // And finally, for this demo, position the viewer to look at the sightline position LookAt lookAt = new LookAt().set(pos.latitude, pos.longitude, pos.altitude, WorldWind.ABSOLUTE, 2e4 /*range*/, 0 /*heading*/, 45 /*tilt*/, 0 /*roll*/); - this.getWorldWindow().getCamera().setFromLookAt(lookAt); + this.getWorldWindow().getCamera().setFromLookAt(this.wwd.getGlobe(), this.wwd.getVerticalExaggeration(), lookAt); } /** diff --git a/worldwind-examples/src/main/java/gov/nasa/worldwindx/PlacemarksMilStd2525Activity.java b/worldwind-examples/src/main/java/gov/nasa/worldwindx/PlacemarksMilStd2525Activity.java index c793506df..35beac70f 100644 --- a/worldwind-examples/src/main/java/gov/nasa/worldwindx/PlacemarksMilStd2525Activity.java +++ b/worldwind-examples/src/main/java/gov/nasa/worldwindx/PlacemarksMilStd2525Activity.java @@ -39,7 +39,7 @@ protected void onCreate(Bundle savedInstanceState) { Position pos = new Position(32.4520, 63.44553, 0); LookAt lookAt = new LookAt().set(pos.latitude, pos.longitude, pos.altitude, WorldWind.ABSOLUTE, 1e5 /*range*/, 0 /*heading*/, 45 /*tilt*/, 0 /*roll*/); - this.getWorldWindow().getCamera().setFromLookAt(lookAt); + this.getWorldWindow().getCamera().setFromLookAt(this.wwd.getGlobe(), this.wwd.getVerticalExaggeration(), lookAt); // The MIL-STD-2525 rendering library takes time initialize, we'll perform this task via the // AsyncTask's background thread and then load the symbols in its post execute handler. diff --git a/worldwind-examples/src/main/java/gov/nasa/worldwindx/PlacemarksSelectDragActivity.java b/worldwind-examples/src/main/java/gov/nasa/worldwindx/PlacemarksSelectDragActivity.java index 5ebd98a2d..f63a606bc 100644 --- a/worldwind-examples/src/main/java/gov/nasa/worldwindx/PlacemarksSelectDragActivity.java +++ b/worldwind-examples/src/main/java/gov/nasa/worldwindx/PlacemarksSelectDragActivity.java @@ -172,7 +172,7 @@ protected void onCreate(Bundle savedInstanceState) { // And finally, for this demo, position the viewer to look at the placemarks LookAt lookAt = new LookAt().set(34.150, -119.150, 0, WorldWind.ABSOLUTE, 2e4 /*range*/, 0 /*heading*/, 45 /*tilt*/, 0 /*roll*/); - this.getWorldWindow().getCamera().setFromLookAt(lookAt); + this.getWorldWindow().getCamera().setFromLookAt(this.wwd.getGlobe(), this.wwd.getVerticalExaggeration(), lookAt); } /** diff --git a/worldwind-tutorials/src/main/assets/look_at_view_tutorial.html b/worldwind-tutorials/src/main/assets/look_at_view_tutorial.html index c65025892..b438232ed 100644 --- a/worldwind-tutorials/src/main/assets/look_at_view_tutorial.html +++ b/worldwind-tutorials/src/main/assets/look_at_view_tutorial.html @@ -58,7 +58,7 @@ <h3>LookAtViewFragment.java</h3> // Apply the new view LookAt lookAt = new LookAt(); lookAt.set(airport.latitude, airport.longitude, airport.altitude, WorldWind.ABSOLUTE, range, heading, tilt, 0 /*roll*/); - wwd.getCamera().setFromLookAt(lookAt); + wwd.getCamera().setFromLookAt(wwd.getGlobe(), wwd.getVerticalExaggeration(), lookAt); return wwd; } diff --git a/worldwind-tutorials/src/main/assets/navigator_events_tutorial.html b/worldwind-tutorials/src/main/assets/navigator_events_tutorial.html index fa40f119e..cb69ff57e 100644 --- a/worldwind-tutorials/src/main/assets/navigator_events_tutorial.html +++ b/worldwind-tutorials/src/main/assets/navigator_events_tutorial.html @@ -85,9 +85,12 @@ <h3>NavigatorEventFragment.java</h3> // Update the status overlay views whenever the navigator stops moving, // and also it is moving but at an (arbitrary) maximum refresh rate of 20 Hz. if (eventAction == WorldWind.NAVIGATOR_STOPPED || elapsedTime > 50) { + // Pick terrain located behind the viewport center point + PickedObject terrainPickedObject = wwd.pick(wwd.getViewport().width / 2f, wwd.getViewport().height / 2f).terrainPickedObject(); + Position terrainPosition = terrainPickedObject != null ? terrainPickedObject.getTerrainPosition() : null; // Get the current camera state to apply to the overlays - event.getCamera().getAsLookAt(lookAt); + event.getCamera().getAsLookAt(wwd.getGlobe(), wwd.getVerticalExaggeration(), terrainPosition, lookAt); // Update the overlays updateOverlayContents(lookAt, event.getCamera()); diff --git a/worldwind-tutorials/src/main/assets/placemarks_picking_tutorial.html b/worldwind-tutorials/src/main/assets/placemarks_picking_tutorial.html index 3a0a0a583..a4c0bc1f9 100644 --- a/worldwind-tutorials/src/main/assets/placemarks_picking_tutorial.html +++ b/worldwind-tutorials/src/main/assets/placemarks_picking_tutorial.html @@ -62,7 +62,7 @@ <h3>PlacemarksPickingFragment.java</h3> // Position the viewer to look near the airports LookAt lookAt = new LookAt().set(34.15, -119.15, 0, WorldWind.ABSOLUTE, 2e4 /*range*/, 0 /*heading*/, 45 /*tilt*/, 0 /*roll*/); - wwd.getCamera().setFromLookAt(lookAt); + wwd.getCamera().setFromLookAt(wwd.getGlobe(), wwd.getVerticalExaggeration(), lookAt); return wwd; } diff --git a/worldwind-tutorials/src/main/assets/placemarks_tutorial.html b/worldwind-tutorials/src/main/assets/placemarks_tutorial.html index 551be0d80..ec8bdf521 100644 --- a/worldwind-tutorials/src/main/assets/placemarks_tutorial.html +++ b/worldwind-tutorials/src/main/assets/placemarks_tutorial.html @@ -90,7 +90,7 @@ <h3>PlacemarksFragment.java</h3> Position pos = airport.getPosition(); LookAt lookAt = new LookAt().set(pos.latitude, pos.longitude, pos.altitude, WorldWind.ABSOLUTE, 1e5 /*range*/, 0 /*heading*/, 80 /*tilt*/, 0 /*roll*/); - wwd.getCamera().setFromLookAt(lookAt); + wwd.getCamera().setFromLookAt(wwd.getGlobe(), wwd.getVerticalExaggeration(), lookAt); return wwd; } diff --git a/worldwind-tutorials/src/main/java/gov/nasa/worldwindx/CameraControlFragment.java b/worldwind-tutorials/src/main/java/gov/nasa/worldwindx/CameraControlFragment.java index 4033042b2..c0c1e9cea 100644 --- a/worldwind-tutorials/src/main/java/gov/nasa/worldwindx/CameraControlFragment.java +++ b/worldwind-tutorials/src/main/java/gov/nasa/worldwindx/CameraControlFragment.java @@ -10,6 +10,7 @@ import gov.nasa.worldwind.WorldWindow; import gov.nasa.worldwind.geom.Camera; import gov.nasa.worldwind.geom.Location; +import gov.nasa.worldwind.geom.Position; import gov.nasa.worldwind.gesture.GestureRecognizer; import gov.nasa.worldwind.gesture.PinchRecognizer; import gov.nasa.worldwind.gesture.RotationRecognizer; @@ -17,6 +18,8 @@ public class CameraControlFragment extends BasicGlobeFragment { + private static final double COLLISION_THRESHOLD = 20.0; // 20m above surface + /** * Creates a new WorldWindow object with a custom WorldWindowController. */ @@ -42,7 +45,7 @@ public WorldWindow createWorldWindow() { * A custom WorldWindController that uses gestures to control the camera directly via the setAsCamera interface * instead of the default setAsLookAt interface. */ - private class CameraController extends BasicWorldWindowController { + private static class CameraController extends BasicWorldWindowController { protected double beginHeading; @@ -189,15 +192,22 @@ protected void gestureDidBegin() { } protected void applyLimits(Camera camera) { - double distanceToExtents = this.wwd.distanceToViewGlobeExtents(); + Position position = camera.position; double minAltitude = 100; - double maxAltitude = distanceToExtents; - camera.position.altitude = WWMath.clamp(camera.position.altitude, minAltitude, maxAltitude); + double maxAltitude = this.wwd.distanceToViewGlobeExtents(); + position.altitude = WWMath.clamp(position.altitude, minAltitude, maxAltitude); + + // Check if camera altitude is not under the surface + double elevation = this.wwd.getGlobe().getElevationAtLocation(position.latitude, position.longitude) + * wwd.getVerticalExaggeration() + COLLISION_THRESHOLD; + if (elevation > position.altitude) { + position.altitude = elevation; + } // Limit the tilt to between nadir and the horizon (roughly) - double r = wwd.getGlobe().getRadiusAt(camera.position.latitude, camera.position.latitude); - double maxTilt = Math.toDegrees(Math.asin(r / (r + camera.position.altitude))); + double r = wwd.getGlobe().getRadiusAt(position.latitude, position.latitude); + double maxTilt = Math.toDegrees(Math.asin(r / (r + position.altitude))); double minTilt = 0; camera.tilt = WWMath.clamp(camera.tilt, minTilt, maxTilt); } diff --git a/worldwind-tutorials/src/main/java/gov/nasa/worldwindx/LookAtViewFragment.java b/worldwind-tutorials/src/main/java/gov/nasa/worldwindx/LookAtViewFragment.java index 5f5ecb7ad..dd03c1e90 100644 --- a/worldwind-tutorials/src/main/java/gov/nasa/worldwindx/LookAtViewFragment.java +++ b/worldwind-tutorials/src/main/java/gov/nasa/worldwindx/LookAtViewFragment.java @@ -39,7 +39,7 @@ public WorldWindow createWorldWindow() { // Apply the new view LookAt lookAt = new LookAt(); lookAt.set(airport.latitude, airport.longitude, airport.altitude, WorldWind.ABSOLUTE, range, heading, tilt, 0 /*roll*/); - wwd.getCamera().setFromLookAt(lookAt); + wwd.getCamera().setFromLookAt(wwd.getGlobe(), wwd.getVerticalExaggeration(), lookAt); return wwd; } diff --git a/worldwind-tutorials/src/main/java/gov/nasa/worldwindx/NavigatorEventFragment.java b/worldwind-tutorials/src/main/java/gov/nasa/worldwindx/NavigatorEventFragment.java index 219cdae1d..1b6e8f7d9 100644 --- a/worldwind-tutorials/src/main/java/gov/nasa/worldwindx/NavigatorEventFragment.java +++ b/worldwind-tutorials/src/main/java/gov/nasa/worldwindx/NavigatorEventFragment.java @@ -18,10 +18,12 @@ import gov.nasa.worldwind.NavigatorEvent; import gov.nasa.worldwind.NavigatorListener; +import gov.nasa.worldwind.PickedObject; import gov.nasa.worldwind.WorldWind; import gov.nasa.worldwind.WorldWindow; import gov.nasa.worldwind.geom.Camera; import gov.nasa.worldwind.geom.LookAt; +import gov.nasa.worldwind.geom.Position; public class NavigatorEventFragment extends BasicGlobeFragment { @@ -78,9 +80,12 @@ public void onNavigatorEvent(WorldWindow wwd, NavigatorEvent event) { // Update the status overlay views whenever the navigator stops moving, // and also it is moving but at an (arbitrary) maximum refresh rate of 20 Hz. if (eventAction == WorldWind.NAVIGATOR_STOPPED || elapsedTime > 50) { + // Pick terrain located behind the viewport center point + PickedObject terrainPickedObject = wwd.pick(wwd.getViewport().width / 2f, wwd.getViewport().height / 2f).terrainPickedObject(); + Position terrainPosition = terrainPickedObject != null ? terrainPickedObject.getTerrainPosition() : null; // Get the current camera state to apply to the overlays - event.getCamera().getAsLookAt(lookAt); + event.getCamera().getAsLookAt(wwd.getGlobe(), wwd.getVerticalExaggeration(), terrainPosition, lookAt); // Update the overlays updateOverlayContents(lookAt, event.getCamera()); diff --git a/worldwind-tutorials/src/main/java/gov/nasa/worldwindx/OmnidirectionalSightlineFragment.java b/worldwind-tutorials/src/main/java/gov/nasa/worldwindx/OmnidirectionalSightlineFragment.java index c3f719988..5a9f3e341 100644 --- a/worldwind-tutorials/src/main/java/gov/nasa/worldwindx/OmnidirectionalSightlineFragment.java +++ b/worldwind-tutorials/src/main/java/gov/nasa/worldwindx/OmnidirectionalSightlineFragment.java @@ -69,6 +69,6 @@ protected void createPlacemark(Position position, RenderableLayer layer) { protected void positionView(WorldWindow wwd) { LookAt lookAt = new LookAt().set(46.230, -122.190, 500, WorldWind.ABSOLUTE, 1.5e4 /*range*/, 45.0 /*heading*/, 70.0 /*tilt*/, 0 /*roll*/); - wwd.getCamera().setFromLookAt(lookAt); + wwd.getCamera().setFromLookAt(wwd.getGlobe(), wwd.getVerticalExaggeration(), lookAt); } } diff --git a/worldwind-tutorials/src/main/java/gov/nasa/worldwindx/PlacemarksFragment.java b/worldwind-tutorials/src/main/java/gov/nasa/worldwindx/PlacemarksFragment.java index 6ff093bc1..2913efdc0 100644 --- a/worldwind-tutorials/src/main/java/gov/nasa/worldwindx/PlacemarksFragment.java +++ b/worldwind-tutorials/src/main/java/gov/nasa/worldwindx/PlacemarksFragment.java @@ -80,7 +80,7 @@ public WorldWindow createWorldWindow() { Position pos = airport.getPosition(); LookAt lookAt = new LookAt().set(pos.latitude, pos.longitude, pos.altitude, WorldWind.ABSOLUTE, 1e5 /*range*/, 0 /*heading*/, 80 /*tilt*/, 0 /*roll*/); - wwd.getCamera().setFromLookAt(lookAt); + wwd.getCamera().setFromLookAt(wwd.getGlobe(), wwd.getVerticalExaggeration(), lookAt); return wwd; } diff --git a/worldwind-tutorials/src/main/java/gov/nasa/worldwindx/PlacemarksPickingFragment.java b/worldwind-tutorials/src/main/java/gov/nasa/worldwindx/PlacemarksPickingFragment.java index 44604ca09..21ea73406 100644 --- a/worldwind-tutorials/src/main/java/gov/nasa/worldwindx/PlacemarksPickingFragment.java +++ b/worldwind-tutorials/src/main/java/gov/nasa/worldwindx/PlacemarksPickingFragment.java @@ -53,7 +53,7 @@ public WorldWindow createWorldWindow() { // Position the viewer to look near the airports LookAt lookAt = new LookAt().set(34.15, -119.15, 0, WorldWind.ABSOLUTE, 2e4 /*range*/, 0 /*heading*/, 45 /*tilt*/, 0 /*roll*/); - wwd.getCamera().setFromLookAt(lookAt); + wwd.getCamera().setFromLookAt(wwd.getGlobe(), wwd.getVerticalExaggeration(), lookAt); return wwd; } diff --git a/worldwind/src/main/java/gov/nasa/worldwind/BasicWorldWindowController.java b/worldwind/src/main/java/gov/nasa/worldwind/BasicWorldWindowController.java index 4593b594a..d8fb544cc 100644 --- a/worldwind/src/main/java/gov/nasa/worldwind/BasicWorldWindowController.java +++ b/worldwind/src/main/java/gov/nasa/worldwind/BasicWorldWindowController.java @@ -12,6 +12,7 @@ import gov.nasa.worldwind.geom.Location; import gov.nasa.worldwind.geom.LookAt; +import gov.nasa.worldwind.geom.Position; import gov.nasa.worldwind.gesture.GestureListener; import gov.nasa.worldwind.gesture.GestureRecognizer; import gov.nasa.worldwind.gesture.MousePanRecognizer; @@ -79,7 +80,7 @@ public void resetOrientation(boolean headingOnly) { this.lookAt.tilt = 0; this.lookAt.roll = 0; } - this.wwd.getCamera().setFromLookAt(this.lookAt); + this.wwd.getCamera().setFromLookAt(this.wwd.getGlobe(), this.wwd.getVerticalExaggeration(), this.lookAt); this.wwd.requestRedraw(); this.gestureDidEnd(); } @@ -88,7 +89,7 @@ public void zoomIn() { this.gestureDidBegin(); this.lookAt.range /= ZOOM_FACTOR; this.applyLimits(lookAt); - this.wwd.getCamera().setFromLookAt(this.lookAt); + this.wwd.getCamera().setFromLookAt(this.wwd.getGlobe(), this.wwd.getVerticalExaggeration(), this.lookAt); this.wwd.requestRedraw(); this.gestureDidEnd(); } @@ -97,7 +98,7 @@ public void zoomOut() { this.gestureDidBegin(); this.lookAt.range *= ZOOM_FACTOR; this.applyLimits(lookAt); - this.wwd.getCamera().setFromLookAt(this.lookAt); + this.wwd.getCamera().setFromLookAt(this.wwd.getGlobe(), this.wwd.getVerticalExaggeration(), this.lookAt); this.wwd.requestRedraw(); this.gestureDidEnd(); } @@ -186,7 +187,7 @@ protected void handlePan(GestureRecognizer recognizer) { this.lookAt.position.longitude = lon; } - this.wwd.getCamera().setFromLookAt(this.lookAt); + this.wwd.getCamera().setFromLookAt(this.wwd.getGlobe(), this.wwd.getVerticalExaggeration(), this.lookAt); this.wwd.requestRedraw(); } else if (state == WorldWind.ENDED || state == WorldWind.CANCELLED) { this.gestureDidEnd(); @@ -205,7 +206,7 @@ protected void handlePinch(GestureRecognizer recognizer) { this.lookAt.range = this.beginLookAt.range / scale; this.applyLimits(this.lookAt); - this.wwd.getCamera().setFromLookAt(this.lookAt); + this.wwd.getCamera().setFromLookAt(this.wwd.getGlobe(), this.wwd.getVerticalExaggeration(), this.lookAt); this.wwd.requestRedraw(); } } else if (state == WorldWind.ENDED || state == WorldWind.CANCELLED) { @@ -226,7 +227,7 @@ protected void handleRotate(GestureRecognizer recognizer) { this.lookAt.heading = WWMath.normalizeAngle360(this.lookAt.heading + headingDegrees); this.lastRotation = rotation; - this.wwd.getCamera().setFromLookAt(this.lookAt); + this.wwd.getCamera().setFromLookAt(this.wwd.getGlobe(), this.wwd.getVerticalExaggeration(), this.lookAt); this.wwd.requestRedraw(); } else if (state == WorldWind.ENDED || state == WorldWind.CANCELLED) { this.gestureDidEnd(); @@ -250,7 +251,7 @@ protected void handleTilt(GestureRecognizer recognizer) { this.lookAt.tilt = this.beginLookAt.tilt + tiltDegrees; this.applyLimits(this.lookAt); - this.wwd.getCamera().setFromLookAt(this.lookAt); + this.wwd.getCamera().setFromLookAt(this.wwd.getGlobe(), this.wwd.getVerticalExaggeration(), this.lookAt); this.wwd.requestRedraw(); } else if (state == WorldWind.ENDED || state == WorldWind.CANCELLED) { this.gestureDidEnd(); @@ -273,7 +274,10 @@ protected void applyLimits(LookAt lookAt) { protected void gestureDidBegin() { if (this.activeGestures++ == 0) { - this.wwd.getCamera().getAsLookAt(this.beginLookAt); + // Pick terrain located behind the viewport center point + PickedObject terrainPickedObject = wwd.pick(wwd.getViewport().width / 2f, wwd.getViewport().height / 2f).terrainPickedObject(); + Position terrainPosition = terrainPickedObject != null ? terrainPickedObject.getTerrainPosition() : null; + this.wwd.getCamera().getAsLookAt(wwd.getGlobe(), wwd.getVerticalExaggeration(), terrainPosition, this.beginLookAt); this.lookAt.set(this.beginLookAt); } } diff --git a/worldwind/src/main/java/gov/nasa/worldwind/Navigator.java b/worldwind/src/main/java/gov/nasa/worldwind/Navigator.java index 06b2721d8..3b4c5d2e5 100644 --- a/worldwind/src/main/java/gov/nasa/worldwind/Navigator.java +++ b/worldwind/src/main/java/gov/nasa/worldwind/Navigator.java @@ -8,74 +8,75 @@ import gov.nasa.worldwind.geom.Camera; import gov.nasa.worldwind.geom.LookAt; import gov.nasa.worldwind.geom.Matrix4; +import gov.nasa.worldwind.geom.Position; import gov.nasa.worldwind.globe.Globe; import gov.nasa.worldwind.util.Logger; @Deprecated public class Navigator { - private final WorldWindow wwd; + private final Camera camera; - public Navigator(WorldWindow wwd) { - if (wwd == null) { + public Navigator(Camera camera) { + if (camera == null) { throw new IllegalArgumentException( - Logger.logMessage(Logger.ERROR, "Navigator", "constructor", "missingWorldWindow")); + Logger.logMessage(Logger.ERROR, "Navigator", "constructor", "missingCamera")); } - this.wwd = wwd; + this.camera = camera; } public double getLatitude() { - return this.wwd.getCamera().position.latitude; + return this.camera.position.latitude; } public Navigator setLatitude(double latitude) { - this.wwd.getCamera().position.latitude = latitude; + this.camera.position.latitude = latitude; return this; } public double getLongitude() { - return this.wwd.getCamera().position.longitude; + return this.camera.position.longitude; } public Navigator setLongitude(double longitude) { - this.wwd.getCamera().position.longitude = longitude; + this.camera.position.longitude = longitude; return this; } public double getAltitude() { - return this.wwd.getCamera().position.altitude; + return this.camera.position.altitude; } public Navigator setAltitude(double altitude) { - this.wwd.getCamera().position.altitude = altitude; + this.camera.position.altitude = altitude; return this; } public double getHeading() { - return this.wwd.getCamera().heading; + return this.camera.heading; } public Navigator setHeading(double headingDegrees) { - this.wwd.getCamera().heading = headingDegrees; + this.camera.heading = headingDegrees; return this; } public double getTilt() { - return this.wwd.getCamera().tilt; + return this.camera.tilt; } public Navigator setTilt(double tiltDegrees) { - this.wwd.getCamera().tilt = tiltDegrees; + this.camera.tilt = tiltDegrees; return this; } public double getRoll() { - return this.wwd.getCamera().roll; + return this.camera.roll; } public Navigator setRoll(double rollDegrees) { - this.wwd.getCamera().roll = rollDegrees; + this.camera.roll = rollDegrees; return this; } @@ -90,7 +91,7 @@ public Camera getAsCamera(Globe globe, Camera result) { Logger.logMessage(Logger.ERROR, "Navigator", "getAsCamera", "missingResult")); } - result.set(this.wwd.camera); + result.set(this.camera); return result; } @@ -106,12 +107,12 @@ public Navigator setAsCamera(Globe globe, Camera camera) { Logger.logMessage(Logger.ERROR, "Navigator", "setAsCamera", "missingCamera")); } - this.wwd.camera.set(camera); + this.camera.set(camera); return this; } - public LookAt getAsLookAt(Globe globe, LookAt result) { + public LookAt getAsLookAt(Globe globe, double verticalExaggeration, Position terrainPosition, LookAt result) { if (globe == null) { throw new IllegalArgumentException( Logger.logMessage(Logger.ERROR, "Navigator", "getAsLookAt", "missingGlobe")); @@ -122,12 +123,12 @@ public LookAt getAsLookAt(Globe globe, LookAt result) { Logger.logMessage(Logger.ERROR, "Navigator", "getAsLookAt", "missingResult")); } - this.wwd.getCamera().getAsLookAt(result); + this.camera.getAsLookAt(globe, verticalExaggeration, terrainPosition, result); return result; } - public Navigator setAsLookAt(Globe globe, LookAt lookAt) { + public Navigator setAsLookAt(Globe globe, double verticalExaggeration, LookAt lookAt) { if (globe == null) { throw new IllegalArgumentException( Logger.logMessage(Logger.ERROR, "Navigator", "setAsLookAt", "missingGlobe")); @@ -138,12 +139,12 @@ public Navigator setAsLookAt(Globe globe, LookAt lookAt) { Logger.logMessage(Logger.ERROR, "Navigator", "setAsLookAt", "missingLookAt")); } - this.wwd.getCamera().setFromLookAt(lookAt); + this.camera.setFromLookAt(globe, verticalExaggeration, lookAt); return this; } - public Matrix4 getAsViewingMatrix(Globe globe, Matrix4 result) { + public Matrix4 getAsViewingMatrix(Globe globe, double verticalExaggeration, Matrix4 result) { if (globe == null) { throw new IllegalArgumentException( Logger.logMessage(Logger.ERROR, "Navigator", "getAsViewingMatrix", "missingGlobe")); @@ -154,7 +155,7 @@ public Matrix4 getAsViewingMatrix(Globe globe, Matrix4 result) { Logger.logMessage(Logger.ERROR, "Navigator", "getAsViewingMatrix", "missingResult")); } - this.wwd.getCamera().computeViewingTransform(result); + this.camera.computeViewingTransform(globe, verticalExaggeration, result); return result; } diff --git a/worldwind/src/main/java/gov/nasa/worldwind/WorldWindow.java b/worldwind/src/main/java/gov/nasa/worldwind/WorldWindow.java index f3e59d82f..cbc7d9654 100644 --- a/worldwind/src/main/java/gov/nasa/worldwind/WorldWindow.java +++ b/worldwind/src/main/java/gov/nasa/worldwind/WorldWindow.java @@ -73,10 +73,10 @@ public class WorldWindow extends GLSurfaceView implements Choreographer.FrameCal protected double verticalExaggeration = 1; - protected Camera camera = new Camera(this); + protected Camera camera = new Camera(); @Deprecated - protected Navigator navigator = new Navigator(this); + protected Navigator navigator = new Navigator(camera); protected NavigatorEventSupport navigatorEvents = new NavigatorEventSupport(this); @@ -1062,6 +1062,6 @@ protected void computeViewingTransform(Matrix4 projection, Matrix4 modelview) { projection.setToPerspectiveProjection(this.viewport.width, this.viewport.height, this.camera.getFieldOfView(), near, far); // Compute a Cartesian transform matrix from the Camera. - this.camera.computeViewingTransform(modelview); + this.camera.computeViewingTransform(globe, verticalExaggeration, modelview); } } diff --git a/worldwind/src/main/java/gov/nasa/worldwind/geom/Camera.java b/worldwind/src/main/java/gov/nasa/worldwind/geom/Camera.java index 6b60a005b..be5bdfd75 100644 --- a/worldwind/src/main/java/gov/nasa/worldwind/geom/Camera.java +++ b/worldwind/src/main/java/gov/nasa/worldwind/geom/Camera.java @@ -5,9 +5,9 @@ package gov.nasa.worldwind.geom; -import gov.nasa.worldwind.PickedObject; +import androidx.annotation.NonNull; + import gov.nasa.worldwind.WorldWind; -import gov.nasa.worldwind.WorldWindow; import gov.nasa.worldwind.globe.Globe; import gov.nasa.worldwind.util.Logger; @@ -15,8 +15,6 @@ public class Camera { private final static double COLLISION_THRESHOLD = 10.0; // 10m above surface - private final WorldWindow wwd; - public final Position position = new Position(); @WorldWind.AltitudeMode @@ -40,15 +38,6 @@ public class Camera { private final Line forwardRay = new Line(); - public Camera(WorldWindow wwd) { - if (wwd == null) { - throw new IllegalArgumentException( - Logger.logMessage(Logger.ERROR, "Camera", "constructor", "missingWorldWindow")); - } - - this.wwd = wwd; - } - public Camera set(double latitude, double longitude, double altitude, @WorldWind.AltitudeMode int altitudeMode, double heading, double tilt, double roll) { this.position.set(latitude, longitude, altitude); @@ -89,6 +78,7 @@ public Camera set(Camera camera) { return this; } + @NonNull @Override public String toString() { return "Camera{" + @@ -102,14 +92,14 @@ public String toString() { '}'; } - public Matrix4 computeViewingTransform(Matrix4 result) { + public Matrix4 computeViewingTransform(Globe globe, double verticalExaggeration, Matrix4 result) { if (result == null) { throw new IllegalArgumentException( Logger.logMessage(Logger.ERROR, "Camera", "computeViewingTransform", "missingResult")); } // Transform by the local cartesian transform at the camera's position. - this.geographicToCartesianTransform(this.position, this.altitudeMode, result); + this.geographicToCartesianTransform(globe, verticalExaggeration, this.position, this.altitudeMode, result); // Transform by the heading, tilt and roll. result.multiplyByRotation(0, 0, 1, -this.heading); // rotate clockwise about the Z axis @@ -122,26 +112,21 @@ public Matrix4 computeViewingTransform(Matrix4 result) { return result; } - public LookAt getAsLookAt(LookAt result) { - Globe globe = this.wwd.getGlobe(); - - this.computeViewingTransform(this.modelview); + public LookAt getAsLookAt(Globe globe, double verticalExaggeration, Position terrainPosition, LookAt result) { + this.computeViewingTransform(globe, verticalExaggeration, this.modelview); - // Pick terrain located behind the viewport center point - PickedObject terrainPickedObject = wwd.pick(wwd.getViewport().width / 2f, wwd.getViewport().height / 2f).terrainPickedObject(); - if (terrainPickedObject != null) { + if (terrainPosition != null) { // Use picked terrain position including approximate rendered altitude - this.originPos.set(terrainPickedObject.getTerrainPosition()); + this.originPos.set(terrainPosition); globe.geographicToCartesian(this.originPos.latitude, this.originPos.longitude, this.originPos.altitude, this.originPoint); - globe.cartesianToLocalTransform(this.originPoint.x, this.originPoint.y, this.originPoint.z, this.origin); } else { // Center is outside the globe - use point on horizon this.modelview.extractEyePoint(this.forwardRay.origin); this.modelview.extractForwardVector(this.forwardRay.direction); this.forwardRay.pointAt(globe.horizonDistance(this.position.altitude), this.originPoint); globe.cartesianToGeographic(this.originPoint.x, this.originPoint.y, this.originPoint.z, this.originPos); - globe.cartesianToLocalTransform(this.originPoint.x, this.originPoint.y, this.originPoint.z, this.origin); } + globe.cartesianToLocalTransform(this.originPoint.x, this.originPoint.y, this.originPoint.z, this.origin); this.modelview.multiplyByMatrix(this.origin); @@ -154,10 +139,8 @@ public LookAt getAsLookAt(LookAt result) { return result; } - public Camera setFromLookAt(LookAt lookAt) { - Globe globe = this.wwd.getGlobe(); - - this.lookAtToViewingTransform(lookAt, this.modelview); + public Camera setFromLookAt(Globe globe, double verticalExaggeration, LookAt lookAt) { + this.lookAtToViewingTransform(globe, verticalExaggeration, lookAt, this.modelview); this.modelview.extractEyePoint(this.originPoint); globe.cartesianToGeographic(this.originPoint.x, this.originPoint.y, this.originPoint.z, this.originPos); @@ -171,7 +154,7 @@ public Camera setFromLookAt(LookAt lookAt) { this.roll = lookAt.roll; // roll passes straight through // Check if camera altitude is not under the surface - double elevation = globe.getElevationAtLocation(this.position.latitude, this.position.longitude) * wwd.getVerticalExaggeration() + COLLISION_THRESHOLD; + double elevation = globe.getElevationAtLocation(this.position.latitude, this.position.longitude) * verticalExaggeration + COLLISION_THRESHOLD; if(elevation > this.position.altitude) { // Set camera altitude above the surface this.position.altitude = elevation; @@ -192,9 +175,9 @@ public Camera setFromLookAt(LookAt lookAt) { return this; } - protected Matrix4 lookAtToViewingTransform(LookAt lookAt, Matrix4 result) { + protected Matrix4 lookAtToViewingTransform(Globe globe, double verticalExaggeration, LookAt lookAt, Matrix4 result) { // Transform by the local cartesian transform at the look-at's position. - this.geographicToCartesianTransform(lookAt.position, lookAt.altitudeMode, result); + this.geographicToCartesianTransform(globe, verticalExaggeration, lookAt.position, lookAt.altitudeMode, result); // Transform by the heading and tilt. result.multiplyByRotation(0, 0, 1, -lookAt.heading); // rotate clockwise about the Z axis @@ -210,21 +193,22 @@ protected Matrix4 lookAtToViewingTransform(LookAt lookAt, Matrix4 result) { return result; } - protected void geographicToCartesianTransform(Position position, @WorldWind.AltitudeMode int altitudeMode, Matrix4 result) { + protected void geographicToCartesianTransform(Globe globe, double verticalExaggeration, Position position, + @WorldWind.AltitudeMode int altitudeMode, Matrix4 result) { switch (altitudeMode) { case WorldWind.ABSOLUTE: - this.wwd.getGlobe().geographicToCartesianTransform( - position.latitude, position.longitude, position.altitude * this.wwd.getVerticalExaggeration(), result); + globe.geographicToCartesianTransform( + position.latitude, position.longitude, position.altitude, result); break; case WorldWind.CLAMP_TO_GROUND: - this.wwd.getGlobe().geographicToCartesianTransform( - position.latitude, position.longitude, this.wwd.getGlobe().getElevationAtLocation( - position.latitude, position.longitude) * this.wwd.getVerticalExaggeration(), result); + globe.geographicToCartesianTransform( + position.latitude, position.longitude, globe.getElevationAtLocation( + position.latitude, position.longitude) * verticalExaggeration, result); break; case WorldWind.RELATIVE_TO_GROUND: - this.wwd.getGlobe().geographicToCartesianTransform( - position.latitude, position.longitude, (position.altitude + this.wwd.getGlobe().getElevationAtLocation( - position.latitude, position.longitude)) * this.wwd.getVerticalExaggeration(), result); + globe.geographicToCartesianTransform( + position.latitude, position.longitude, (position.altitude + globe.getElevationAtLocation( + position.latitude, position.longitude)) * verticalExaggeration, result); break; } } diff --git a/worldwind/src/test/java/gov/nasa/worldwind/geom/FrustumTest.java b/worldwind/src/test/java/gov/nasa/worldwind/geom/FrustumTest.java index 1f899aafe..8298f1ecb 100644 --- a/worldwind/src/test/java/gov/nasa/worldwind/geom/FrustumTest.java +++ b/worldwind/src/test/java/gov/nasa/worldwind/geom/FrustumTest.java @@ -176,102 +176,100 @@ public void testIntersectsSegment() throws Exception { assertFalse("outside far", frustum.intersectsSegment(new Vec3(0, 0, 2), new Vec3(0, 0, 1.0000001))); } -// NOTE Navigator is now dependent on WorldWindow instance which is dependent on Android Context. -// Move these tests to androidTest section? -// @Test -// public void testSetToModelviewProjection() throws Exception { -// // The expected test values were obtained via SystemOut on Frustum object -// // at a time in the development cycle when the setToModelviewProjection -// // was known to be working correctly (via observed runtime behavior). -// // This unit test simply tests for changes in the behavior since that time. -// -// // Create a Frustum similar to the way the WorldWindow does it. -// -// // Setup a Camera, looking near Oxnard Airport. -// LookAt lookAt = new LookAt().set(34.15, -119.15, 0, WorldWind.ABSOLUTE, 2e4 /*range*/, 0 /*heading*/, 45 /*tilt*/, 0 /*roll*/); -// Camera camera = new Camera(wwd); -// camera.setFromLookAt(lookAt); -// -// // Compute a perspective projection matrix given the viewport, field of view, and clip distances. -// Viewport viewport = new Viewport(0, 0, 100, 100); // screen coordinates -// double nearDistance = camera.position.altitude * 0.75; -// double farDistance = globe.horizonDistance(camera.position.altitude) + globe.horizonDistance(160000); -// Matrix4 projection = new Matrix4(); -// projection.setToPerspectiveProjection(viewport.width, viewport.height, 45d /*fovy*/, nearDistance, farDistance); -// -// // Compute a Cartesian viewing matrix using this Camera's properties as a Camera. -// Matrix4 modelview = new Matrix4(); -// camera.computeViewingTransform(modelview); -// -// // Compute the Frustum -// Frustum frustum = new Frustum(); -// frustum.setToModelviewProjection(projection, modelview, viewport); -// -// // Evaluate the results with known values captured on 07/19/2016 -// //System.out.println(frustumToString(frustum)); -// Plane bottom = new Plane(0.17635740224291638, 0.9793994030381801, 0.09836094754823524, -2412232.453445458); -// Plane left = new Plane(-0.12177864151960982, 0.07203573632653165, 0.9899398038070459, 1737116.8972521012); -// Plane right = new Plane(0.7782605589154529, 0.07203573632653174, -0.6237959242640989, 1737116.8972521003); -// Plane top = new Plane(0.48012451515292665, -0.8353279303851167, 0.2677829319947119, 5886466.24794966); -// Plane near = new Plane(0.8577349603804412, 0.1882384504636923, 0.4783900328269719, 4528686.830908618); -// Plane far = new Plane(-0.8577349603804412, -0.1882384504636923, -0.4783900328269719, -2676528.6881595235); -// -// assertEquals("left", left, frustum.left); -// assertEquals("right", right, frustum.right); -// assertEquals("bottom", bottom, frustum.bottom); -// assertEquals("top", top, frustum.top); -// assertEquals("near", near, frustum.near); -// assertEquals("far", far, frustum.far); -// assertEquals("viewport", viewport, frustum.viewport); -// } -// -// @Test -// public void testSetToModelviewProjection_SubViewport() throws Exception { -// // The expected test values were obtained via SystemOut on Frustum object -// // at a time in the development cycle when the setToModelviewProjection -// // was known to be working correctly (via observed runtime behavior). -// // This unit test simply tests for changes in the behavior since that time. -// -// // Create a Frustum similar to the way the WorldWindow does it when picking -// -// // Setup a Camera, looking near Oxnard Airport. -// LookAt lookAt = new LookAt().set(34.15, -119.15, 0, WorldWind.ABSOLUTE, 2e4 /*range*/, 0 /*heading*/, 45 /*tilt*/, 0 /*roll*/); -// Camera camera = new Camera(wwd); -// camera.setFromLookAt(lookAt); -// -// // Compute a perspective projection matrix given the viewport, field of view, and clip distances. -// Viewport viewport = new Viewport(0, 0, 100, 100); // screen coordinates -// Viewport pickViewport = new Viewport(49, 49, 3, 3); // 3x3 viewport centered on a pick point -// double nearDistance = camera.position.altitude * 0.75; -// double farDistance = globe.horizonDistance(camera.position.altitude) + globe.horizonDistance(160000); -// Matrix4 projection = new Matrix4(); -// projection.setToPerspectiveProjection(viewport.width, viewport.height, 45d /*fovy*/, nearDistance, farDistance); -// -// // Compute a Cartesian viewing matrix using this Camera's properties as a Camera. -// Matrix4 modelview = new Matrix4(); -// camera.computeViewingTransform(modelview); -// -// // Compute the Frustum -// Frustum frustum = new Frustum(); -// frustum.setToModelviewProjection(projection, modelview, viewport, pickViewport); -// -// // Evaluate the results with known values captured on 06/03/2016 -// //System.out.println(frustumToString(frustum)); -// Plane bottom = new Plane(-0.15728647066358287, 0.9836490211411795, -0.0877243942936819, -4453465.7217097925); -// Plane left = new Plane(-0.4799755263103557, 0.001559364875310035, 0.8772804925018466, 37603.54528193692); -// Plane right = new Plane(0.5012403287200531, 0.003118408767628064, -0.8653024953109584, 75199.35019616158); -// Plane top = new Plane(0.17858448447919384, -0.9788701700756626, 0.09960307243927863, 4565806.392885632); -// Plane near = new Plane(0.8577349603809148, 0.18823845046641746, 0.4783900328250505, 4528686.830896157); -// Plane far = new Plane(-0.8577349603804465, -0.1882384504638284, -0.4783900328269087, -2676528.6881588553); -// -// assertEquals("left", left, frustum.left); -// assertEquals("right", right, frustum.right); -// assertEquals("bottom", bottom, frustum.bottom); -// assertEquals("top", top, frustum.top); -// assertEquals("near", near, frustum.near); -// assertEquals("far", far, frustum.far); -// assertEquals("viewport", pickViewport, frustum.viewport); -// } + @Test + public void testSetToModelviewProjection() throws Exception { + // The expected test values were obtained via SystemOut on Frustum object + // at a time in the development cycle when the setToModelviewProjection + // was known to be working correctly (via observed runtime behavior). + // This unit test simply tests for changes in the behavior since that time. + + // Create a Frustum similar to the way the WorldWindow does it. + + // Setup a Camera, looking near Oxnard Airport. + LookAt lookAt = new LookAt().set(34.15, -119.15, 0, WorldWind.ABSOLUTE, 2e4 /*range*/, 0 /*heading*/, 45 /*tilt*/, 0 /*roll*/); + Camera camera = new Camera(); + camera.setFromLookAt(globe, 1.0, lookAt); + + // Compute a perspective projection matrix given the viewport, field of view, and clip distances. + Viewport viewport = new Viewport(0, 0, 100, 100); // screen coordinates + double nearDistance = camera.position.altitude * 0.75; + double farDistance = globe.horizonDistance(camera.position.altitude) + globe.horizonDistance(160000); + Matrix4 projection = new Matrix4(); + projection.setToPerspectiveProjection(viewport.width, viewport.height, 45d /*fovy*/, nearDistance, farDistance); + + // Compute a Cartesian viewing matrix using this Camera's properties as a Camera. + Matrix4 modelview = new Matrix4(); + camera.computeViewingTransform(globe, 1.0, modelview); + + // Compute the Frustum + Frustum frustum = new Frustum(); + frustum.setToModelviewProjection(projection, modelview, viewport); + + // Evaluate the results with known values captured on 07/19/2016 + //System.out.println(frustumToString(frustum)); + Plane bottom = new Plane(0.17635740224291638, 0.9793994030381801, 0.09836094754823524, -2412232.453445458); + Plane left = new Plane(-0.12177864151960982, 0.07203573632653165, 0.9899398038070459, 1737116.8972521012); + Plane right = new Plane(0.7782605589154529, 0.07203573632653174, -0.6237959242640989, 1737116.8972521003); + Plane top = new Plane(0.48012451515292665, -0.8353279303851167, 0.2677829319947119, 5886466.24794966); + Plane near = new Plane(0.8577349603804412, 0.1882384504636923, 0.4783900328269719, 4528686.830908618); + Plane far = new Plane(-0.8577349603804412, -0.1882384504636923, -0.4783900328269719, -2676528.6881595235); + + assertEquals("left", left, frustum.left); + assertEquals("right", right, frustum.right); + assertEquals("bottom", bottom, frustum.bottom); + assertEquals("top", top, frustum.top); + assertEquals("near", near, frustum.near); + assertEquals("far", far, frustum.far); + assertEquals("viewport", viewport, frustum.viewport); + } + + @Test + public void testSetToModelviewProjection_SubViewport() throws Exception { + // The expected test values were obtained via SystemOut on Frustum object + // at a time in the development cycle when the setToModelviewProjection + // was known to be working correctly (via observed runtime behavior). + // This unit test simply tests for changes in the behavior since that time. + + // Create a Frustum similar to the way the WorldWindow does it when picking + + // Setup a Camera, looking near Oxnard Airport. + LookAt lookAt = new LookAt().set(34.15, -119.15, 0, WorldWind.ABSOLUTE, 2e4 /*range*/, 0 /*heading*/, 45 /*tilt*/, 0 /*roll*/); + Camera camera = new Camera(); + camera.setFromLookAt(globe, 1.0, lookAt); + + // Compute a perspective projection matrix given the viewport, field of view, and clip distances. + Viewport viewport = new Viewport(0, 0, 100, 100); // screen coordinates + Viewport pickViewport = new Viewport(49, 49, 3, 3); // 3x3 viewport centered on a pick point + double nearDistance = camera.position.altitude * 0.75; + double farDistance = globe.horizonDistance(camera.position.altitude) + globe.horizonDistance(160000); + Matrix4 projection = new Matrix4(); + projection.setToPerspectiveProjection(viewport.width, viewport.height, 45d /*fovy*/, nearDistance, farDistance); + + // Compute a Cartesian viewing matrix using this Camera's properties as a Camera. + Matrix4 modelview = new Matrix4(); + camera.computeViewingTransform(globe, 1.0, modelview); + + // Compute the Frustum + Frustum frustum = new Frustum(); + frustum.setToModelviewProjection(projection, modelview, viewport, pickViewport); + + // Evaluate the results with known values captured on 06/03/2016 + //System.out.println(frustumToString(frustum)); + Plane bottom = new Plane(-0.15728647066358287, 0.9836490211411795, -0.0877243942936819, -4453465.7217097925); + Plane left = new Plane(-0.4799755263103557, 0.001559364875310035, 0.8772804925018466, 37603.54528193692); + Plane right = new Plane(0.5012403287200531, 0.003118408767628064, -0.8653024953109584, 75199.35019616158); + Plane top = new Plane(0.17858448447919384, -0.9788701700756626, 0.09960307243927863, 4565806.392885632); + Plane near = new Plane(0.8577349603809148, 0.18823845046641746, 0.4783900328250505, 4528686.830896157); + Plane far = new Plane(-0.8577349603804465, -0.1882384504638284, -0.4783900328269087, -2676528.6881588553); + + assertEquals("left", left, frustum.left); + assertEquals("right", right, frustum.right); + assertEquals("bottom", bottom, frustum.bottom); + assertEquals("top", top, frustum.top); + assertEquals("near", near, frustum.near); + assertEquals("far", far, frustum.far); + assertEquals("viewport", pickViewport, frustum.viewport); + } @Test public void testIntersectsViewport() throws Exception {