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.
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...