javajavafx-8worldwindmercator

RayCastingSupport.intersectRayWithTerrain always returns null


I use my own interaction method because I embed NASA WorldWind into JavaFX not Swing. View is defined in FXML as follow:

<?xml version="1.0" encoding="UTF-8"?>
...
<Pane xmlns:fx="http://javafx.com/fxml" fx:id="_mainPane"
   fx:controller="view.MainCtrl" prefWidth="1600" prefHeight="900">
   <stylesheets><URL value="@NavDb.css" /></stylesheets>
   <BorderPane><SwingNode fx:id="_worldWindFxContainer" /></BorderPane>
   ...

Controller attributes:

   @FXML private SwingNode           _worldWindFxContainer;

   private final WorldWindowGLJPanel _worldWind   = new WorldWindowGLJPanel();
   private final RenderableLayer     _routeLayer  = new RenderableLayer();
   private final RenderableLayer     _alertLayer  = new RenderableLayer();
   private final Preferences         _preferences = new Preferences();

WW initialization code:

   private void initWorldWind() {
      WorldWind.setOfflineMode( _preferences.get( "WorldWind/offline", false ));
      final OrbitView orbitVw = new FlatOrbitView();
      final EarthFlat globe   = new EarthFlat();
      final Model     model   = new BasicModel();
      globe.setProjection( FlatGlobe.PROJECTION_MERCATOR );
      model.setGlobe( globe );
      orbitVw.getOrbitViewLimits().setZoomLimits( 1.2E+04, 2.2E+07 );
      _worldWind.setModelAndView( model, orbitVw );
      _worldWind.getSceneController().setDeepPickEnabled( true );
      _routeLayer.setName( "Route-Layer" );
      _routeLayer.setPickEnabled( false );
      _alertLayer.setName( "Alert-Layer" );
      _alertLayer.setPickEnabled( true );
      _alertLayer.setEnabled( true );
      final LayerList layers = model.getLayers();
      layers.add( _routeLayer );
      layers.add( _alertLayer );
      layers.removeIf( l -> l instanceof CompassLayer  );
      layers.removeIf( l -> l instanceof WorldMapLayer );
      for(int i = 0; i < layers.size(); i++) {
         final Layer l = layers.get( i );
         if( l instanceof SkyGradientLayer ) {
            layers.set( i, new SkyColorLayer());
          }
      }
      final double lat        = _preferences.get( "Startup/initial-location-lat", 0.0 );
      final double lon        = _preferences.get( "Startup/initial-location-lon", 0.0 );
      final double zoomFactor = _preferences.get( "Startup/initial-zoom", 1.0 );
      orbitVw.setEyePosition( Position.fromDegrees( lat, lon ));
      orbitVw.setZoom( zoomFactor );
      Platform.runLater(() -> {
         final Interactions handler = new Interactions( _worldWind );
         handler.setPicker( this );
         _worldWindFxContainer.addEventHandler( InputEvent .ANY, handler );
         _worldWindFxContainer.addEventFilter ( MouseEvent .ANY, event -> {
            handler.handle( event );
            event.consume();
         });
         _worldWindFxContainer.addEventFilter ( ScrollEvent.ANY, event -> {
            handler.handle( event );
            event.consume();
         });
      });
      _worldWind.redrawNow();
   }

From JavaFx init code:

   SwingUtilities.invokeLater( this::initWorldWind );

Interactions class:

public final class Interactions implements EventHandler<InputEvent> {

   private final WorldWindowGLJPanel _wwPanel;
   private final SceneController     _sceneController;
   private final OrbitView           _view;

   public Interactions( WorldWindowGLJPanel wwPanel ) {
      _wwPanel         = wwPanel;
      _sceneController = _wwPanel.getSceneController();
      _view            = (OrbitView)_sceneController.getView();
   }

   private Position getPositionFromScreenPoint( double x, double y ) {
      final View vw  = _sceneController.getView();
      final Line ray = vw.computeRayFromScreenPoint( x, y );
      if( ray != null ) {
         final Globe globe = _sceneController.getModel().getGlobe();
         final Vec4 origin = ray.getOrigin();
         final Vec4 direction = ray.getDirection().normalize3();
         final Position pos =
            RayCastingSupport.intersectRayWithTerrain( globe, origin, direction );
         return pos;
      }
      return null;
   }

Interactions.getPositionFromScreenPoint is called from FX Mouse handler.

The problem is: RayCastingSupport.intersectRayWithTerrain() always returns null after I switch from spheric representation of the world to flat one.


Solution

  • I haven't found the true answer but wrote a simplified approach to handle mouse clicks for moving the flat map:

       private Position getPositionFromScreenPoint( double x, double y ) {
          final View           vw        = _sceneController.getView();
          final Line           ray       = vw.computeRayFromScreenPoint( x, y );
          final Vec4           origin    = ray.getOrigin();
          final Vec4           direction = ray.getDirection().normalize3();
          final Globe          globe     = _sceneController.getModel().getGlobe();
          final double         gme       = globe.getMaxElevation();
          final Intersection[] inters    = globe.intersect( new Line( origin, direction ), gme );
          if( inters != null ) {
             final Vec4     pt  = inters[0].getIntersectionPoint();
             final Position pos = globe.computePositionFromPoint( pt );
             return pos;
          }
          return null;
       }
    

    I don't understand why I have to check null for inters, but sometimes, it's null...