[vtkusers] VTK and JavaFX?

nagao saichi nagao-saichi at jcom.home.ne.jp
Sat May 20 10:15:16 EDT 2017


I created SimpleVTKFX and SimpleVTKFX. 
 Idea of this class is vtk rendering image copy to javafx ImageView
 pane by interval timmer. Copy method is , image file create by
  vtkPNGWriter , after read from file to javaFX ImageView.

comment include japanese.

 /****************************** SimpleVTKFX  */ 
package vtk.sample;

import java.lang.reflect.InvocationTargetException;
import java.util.concurrent.Callable;

import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import vtk.vtkActor;
import vtk.vtkConeSource;
import vtk.vtkDataSetMapper;
import vtk.vtkFXCanvas;
import vtk.vtkPolyDataMapper;
import vtk.vtkShrinkFilter;
import vtk.vtkSphereSource;

/**
 * <p>
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.  A HTML version of the GNU General Public License can
be
 * seen at http://www.gnu.org/licenses/gpl.html
 * </p>
 * <p>
 * This program is distributed in the hope that it will be useful, but
WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 * </p>
 *
 * @author SaichiNagao
 * date: 2017/05/12
 */
public class SimpleVTKFX extends Application {
	vtkFXCanvas pane = null;

  // -----------------------------------------------------------------
	// copy from Demo.java
  public class PipelineBuilder implements Callable<vtkActor> {
      private vtkActor actor;
      private vtkDataSetMapper mapper;
      private vtkShrinkFilter shrink;
      private vtkSphereSource sphere;

      @Override
      public  vtkActor call() throws Exception {
          // New
          actor = new vtkActor();
          mapper = new vtkDataSetMapper();
          shrink = new vtkShrinkFilter();
          sphere = new vtkSphereSource();

          // Settings
          sphere.SetPhiResolution(30);
          sphere.SetThetaResolution(30);
          double[] center = new double[3];
          sphere.SetCenter(GetRandomCenter(center));
          actor.GetProperty().SetColor(Math.random(), Math.random(),
Math.random());
          shrink.SetShrinkFactor(0.8);

          // Binding
          shrink.SetInputConnection(sphere.GetOutputPort());
          mapper.SetInputConnection(shrink.GetOutputPort());

          // Update
          actor.SetMapper(mapper);

          // Wait some time
          Thread.sleep((long) (Math.random() * 50));

          // Return
          return actor;
      }

      public double[] GetRandomCenter(double[] center) {
          for (int i = 0; i < 3; i++) {
              center[i] = Math.random() * 10;
          }
          return center;
      }
  }
  // -----------------------------------------------------------------

  @Override
	public void start(Stage stage) throws Exception {
		pane = new vtkFXCanvas();

    // build VTK Pipeline

    vtkConeSource cone = new vtkConeSource();
    cone.SetResolution(16);

    vtkPolyDataMapper coneMapper = new vtkPolyDataMapper();
    coneMapper.SetInputConnection(cone.GetOutputPort());

    vtkActor coneActor = new vtkActor();
    coneActor.SetMapper(coneMapper);
    pane.addActor(coneActor);
    pane.getCanvas3D().addToPlaneWidget(coneActor);
    pane.getCanvas3D().addToBoxWidget(coneActor);
/*
    // more vtk objects add to canvas
		PipelineBuilder bp = new PipelineBuilder();
		for(int i=0;i< 100;i++) {
	    pane.addActor(bp.call());
		}
*/
    BorderPane border = new BorderPane();
    Button exit = new Button("Exit");
    EventHandler<MouseEvent>handler = ( event ) -> stop();
    exit.addEventHandler(MouseEvent.MOUSE_CLICKED, handler);
    border.setCenter(pane);
    border.setBottom(exit);
    BorderPane.setAlignment(exit, Pos.CENTER);

		Scene thiscene = new Scene(border, 400, 400);
    pane.renderStart();

    stage.setScene(thiscene);
    stage.setTitle("VTK FXCanvas Test...");
    stage.show();
	}
  @Override
  public void stop() {
  	pane.finalize();
  	System.exit(0);
  }

  // -----------------------------------------------------------------
  public static void main(String[] args) throws InterruptedException,
InvocationTargetException {
    launch(args);
  }
}

/*****************************  SimpleVTKFX*/
package vtk;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseWheelEvent;
import java.io.File;

import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

import javafx.embed.swing.SwingNode;
import javafx.event.EventHandler;
import javafx.scene.image.ImageView;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.ScrollEvent;
import javafx.scene.layout.StackPane;

/**
 * JavaFXのアプリケーションにVTKCanvasを表示させるためのクラス。このクラスは、
 * StackPaneを継承し、VTKCanvasをのせるためのSwingNodeと表示させるためのImageView
 * を保存する。JavaFXでは、直接AWTを表示することができ無いので、いったんSwingNode
 * に乗せたVTKCanvasでレンダリングを行い、タイマーを使用して、一定間隔で描画領域を
 * イメージとして、ImageViewで表示する。マウスイベントは、ImageViewで捕捉し、
 * AWTのイベントに変換してVTKCanvasのメソッドを実行する。
 * <p>
 * vtkCanvasでマウスによる入力は、直接は受け付けられないが、表示であれば、上記方法で
 * 実現可能である。
 * </p>
 * <p>
 *  This class can controll Widget and draw actors. TrackballCamera
 *  interaction enable. vtkCanvas sources are not change.
 *  Resize pane is bad, resize smaller is bad.
 * </p>
 * <p>
 *  Idea of this class is vtk rendering image copy to javafx ImageView
 *  pane by interval timmer. Copy method is , image file create by
 *  vtkPNGWriter , after read from file to javaFX ImageView.
 * </p>
 * <p>
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.  A HTML version of the GNU General Public License can
be
 * seen at http://www.gnu.org/licenses/gpl.html
 * </p>
 * <p>
 * This program is distributed in the hope that it will be useful, but
WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 * </p>
 *
 * @author SaichiNagao
 * date: 2017/05/12
 */
public class vtkFXCanvas extends StackPane {
	//
  // -----------------------------------------------------------------
  // Load VTK library and print which library was not properly loaded
  static {
      if (!vtkNativeLibrary.LoadAllNativeLibraries()) {
          for (vtkNativeLibrary lib : vtkNativeLibrary.values()) {
              if (!lib.IsLoaded()) {
                  System.out.println(lib.GetLibraryName() + " not loaded");
              }
          }
      }
      vtkNativeLibrary.DisableOutputWindow(null);
  }

  // -----------------------------------------------------------------
	/**
	 * vtkのレンダリングを行うパネル
	 */
  private vtkCanvas canvas3D = new vtkCanvas();
	/**
   * vtkCanvasのイメージをFXのImageViewにコピーする方法は、ファイルを介して
   * 行うのが、簡単で早いみたい。一旦イメージファイルに保存して、ファイルから
   * FXのImageViewに表示する。
   */
  vtkPNGWriter writer = new vtkPNGWriter();
	File tempFile = new File("__temp__.png");
	String uri = tempFile.toURI().toString();
	/**
	 * StackPaneに実装するノード、SwingNodeは、vtkCanvasをのせるために
	 * 使用する。
	 */
  SwingNode swingNode = new SwingNode();
  /**
   * vtkCanvasのレンダリングされたイメージを表示するために、ImageView
   * を使用する。
   */
  ImageView imageNode = new ImageView();

  private Timer repaintimer;
  /**
   * 再描画時間間隔、イメージのコピーの時間により調整される。
   */
  private int repaintInterval = 200;
	/**
   * イメージの設定フラグ
   */
  private int setimageflag = -1;
  /**
   * コンストラクタ
   */
  public vtkFXCanvas() {
    EventHandler<MouseEvent>mHandler0 = ( event ) -> mousePressed(event);
    EventHandler<MouseEvent>mHandler1 = ( event ) -> mouseDragged(event);
    EventHandler<MouseEvent>mHandler2 = ( event ) -> mouseReleased(event);
    EventHandler<ScrollEvent>mHandler3 = ( event ) ->
mouseWheelMoved(event);
    EventHandler<MouseEvent>mHandler4 = ( event ) -> mouseMoved(event);
    EventHandler<MouseEvent>mHandler5 = ( event ) -> mouseEntered(event);
    EventHandler<MouseEvent>mHandler6 = ( event ) -> mouseExited(event);

    EventHandler<KeyEvent>kHandler0 = ( event ) -> keyTyped(event);
//    EventHandler<KeyEvent>kHandler1 = ( event ) -> keyPressed(event);
//    EventHandler<KeyEvent>kHandler2 = ( event ) -> keyReleased(event);

    imageNode.addEventHandler(MouseEvent.MOUSE_PRESSED ,  mHandler0	);
    imageNode.addEventHandler(MouseEvent.MOUSE_DRAGGED ,  mHandler1	);
    imageNode.addEventHandler(MouseEvent.MOUSE_RELEASED ,  mHandler2	);
    imageNode.addEventHandler(ScrollEvent.SCROLL ,  mHandler3	);
    imageNode.addEventHandler(MouseEvent.MOUSE_MOVED ,  mHandler4	);
    imageNode.addEventHandler(MouseEvent.MOUSE_ENTERED ,  mHandler5	);
    imageNode.addEventHandler(MouseEvent.MOUSE_EXITED ,  mHandler6	);
    /*
     * キーイベントは、swingNodeにキーフォーカスがあると、
     * vtkCanvasに送られる。
     * swingNode exists keyfocus , keyevent sends to vtkCanvas
     */
//    imageNode.addEventHandler(KeyEvent.KEY_TYPED ,  kHandler1	);
//    imageNode.addEventHandler(KeyEvent.KEY_PRESSED ,  kHandler0	);
//    imageNode.addEventHandler(KeyEvent.KEY_RELEASED ,  kHandler2	);
    // only for setimage method execute at key type.
    swingNode.addEventHandler(KeyEvent.KEY_TYPED ,  kHandler0	);

    getChildren().add(swingNode);
    getChildren().add(imageNode);
    // can not see , but must be true
    swingNode.setVisible(true);
    imageNode.setFocusTraversable(false);
    swingNode.setFocusTraversable(true);
    imageNode.setVisible(true);
  	imageNode.autosize();
//    imageNode.requestFocus();

    JPanel jcomp = new JPanel();
    jcomp.setLayout(new BorderLayout());
    jcomp.add(canvas3D, BorderLayout.CENTER);
    swingNode.setContent(jcomp);
    /*
     * 以下の行を入れないと、小さくしたときリサイズしない。
     * 最小のサイズが、起動した時のサイズになっている。
     * if below line does not insert , then smaller resize is bad.
     */
    setMinSize(1, 1);
 }
  /**
   * マウスの押下イベント処理メソッド
   * @param e FXのマウスイベントオブジェクト
   */
  private void mousePressed(MouseEvent e) {
  	setimageflag = 1;
  	canvas3D.mousePressed(toSwingEvent(e));
  }
  /**
   * マウスのドラッグイベント処理メソッド
   * @param e FXのマウスイベントオブジェクト
   */
  private void mouseDragged(MouseEvent e) {
  	setimageflag = 2;
  	canvas3D.mouseDragged(toSwingEvent(e));
  }
  /**
   * マウスのリリースイベント処理メソッド
   * @param e FXのマウスイベントオブジェクト
   */
  private void mouseReleased(MouseEvent e) {
  	setimageflag = 4;
  	canvas3D.mouseReleased(toSwingEvent(e));
  }
  /**
   * マウスの出域イベント処理メソッド
   * @param e FXのマウスイベントオブジェクト
   */
  private void mouseEntered(MouseEvent e) {
  	setimageflag = 8;
  	canvas3D.mouseEntered(toSwingEvent(e));
  }
  /**
   * マウスの入域イベント処理メソッド
   * @param e FXのマウスイベントオブジェクト
   */
  private void mouseExited(MouseEvent e) {
  	setimageflag = 16;
  	canvas3D.mouseExited(toSwingEvent(e));
  }
  /**
   * マウスのムーブイベント処理メソッド
   * @param e FXのマウスイベントオブジェクト
   */
  private void mouseMoved(MouseEvent e) {
  	// not repaint on mouse Move
  	setimageflag = 0;
  	canvas3D.mouseMoved(toSwingEvent(e));
  }
  /**
   * マウスのスクロールイベント処理メソッド
   * @param e FXのマウスイベントオブジェクト
   */
  private void mouseWheelMoved(ScrollEvent e) {
  	int modifiers = 0;
  	int scrollType = MouseWheelEvent.WHEEL_UNIT_SCROLL;
  	int scrollAmount = e.getTouchCount();
  	int wheelRotation = (int)e.getDeltaY();
  	//  System.out.println("wheelRotation="+wheelRotation);
  	if(e.isShiftDown()) modifiers+= java.awt.event.InputEvent.SHIFT_MASK;
  	if(e.isAltDown()) modifiers+= java.awt.event.InputEvent.ALT_MASK;
  	if(e.isControlDown()) modifiers+= java.awt.event.InputEvent.CTRL_MASK;

  	MouseWheelEvent mwe = new MouseWheelEvent(canvas3D,
MouseWheelEvent.WHEEL_UNIT_SCROLL,
  			System.currentTimeMillis(),
  			modifiers, (int)e.getX(), (int)e.getY(), e.getTouchCount(),
  			false, scrollType, scrollAmount, wheelRotation);

  	setimageflag = 64;
  	canvas3D.mouseWheelMoved(mwe);
  }
  /**
   * FXのマウスイベントオブジェクトをSwingのマウスイベントオブジェクトに変換する。
   * @param e FXのマウスイベントオブジェクト
   * @return Swingのマウスイベントオブジェクト
   */
  private java.awt.event.MouseEvent toSwingEvent(MouseEvent e) {
  	int modifiers = 0;
  	int button = 0;
  	if(e.isShiftDown()) modifiers+= java.awt.event.InputEvent.SHIFT_MASK;
  	if(e.isAltDown()) modifiers+= java.awt.event.InputEvent.ALT_MASK;
  	if(e.isControlDown()) modifiers+= java.awt.event.InputEvent.CTRL_MASK;
  	if(e.getButton() == MouseButton.PRIMARY) modifiers +=
java.awt.event.InputEvent.BUTTON1_MASK;
  	if(e.getButton() == MouseButton.MIDDLE) modifiers +=
java.awt.event.InputEvent.BUTTON2_MASK;
  	if(e.getButton() == MouseButton.SECONDARY) modifiers +=
java.awt.event.InputEvent.BUTTON3_MASK;

  	if(e.getButton() == MouseButton.PRIMARY) button = 0;
  	if(e.getButton() == MouseButton.MIDDLE) button = 1;
  	if(e.getButton() == MouseButton.SECONDARY) button = 2;
//  	System.out.println("button="+button+", modifiers="+modifiers+",
setimageflag="+setimageflag);
//  	System.out.println("X="+e.getX()+", Y="+e.getY()+",
getClickCount="+e.getClickCount());

  	java.awt.event.MouseEvent event = new java.awt.event.MouseEvent(canvas3D,
  			button,  System.currentTimeMillis(), modifiers,
  			(int)e.getX(), (int)e.getY(), e.getClickCount(), false);
  	return event;
  }
  /**
   * キータイプイベント処理メソッド
   * @param e FXのキーイベント
   */
  private void keyTyped(KeyEvent e) {
  	setimageflag = 128;
  	canvas3D.keyTyped(toSwingEvent(e));
  }
  /**
   * キー押下イベント処理メソッド
   * @param e FXのキーイベント
   */
  private void keyPressed(KeyEvent e) {
  	setimageflag = 256;
  	canvas3D.keyPressed(toSwingEvent(e));
  }
  /**
   * キーリリースイベント処理メソッド
   * @param e FXのキーイベント
   */
  private void keyReleased(KeyEvent e) {
  	setimageflag = 512;
  	canvas3D.keyReleased(toSwingEvent(e));
  }
  /**
   * FXのキーベントオブジェクトをSwingのキーイベントオブジェクトに変換する。
   * @param e FXのキーイベントオブジェクト
   * @return Swingのキーイベントオブジェクト
   */
  private java.awt.event.KeyEvent toSwingEvent(KeyEvent e) {
  	int id = 0;
  	long when = System.currentTimeMillis();
  	int modifiers = 0;
  	if(e.isShiftDown()) modifiers+= java.awt.event.InputEvent.SHIFT_MASK;
  	if(e.isControlDown()) modifiers+= java.awt.event.InputEvent.CTRL_MASK;
  	if(e.isAltDown()) modifiers+= java.awt.event.InputEvent.ALT_MASK;

  	char keychar = e.getCharacter().charAt(0);
  	int keycode = Integer.valueOf(keychar);
//  	System.out.println("keyChar="+keychar+", keyCode="+keycode+",
setimageflag="+setimageflag);

  	java.awt.event.KeyEvent event = new java.awt.event.KeyEvent(canvas3D,
  			id, when, modifiers, keycode, keychar);
  	return event;
  }
  /**
   * vtkCanvasのイメージを、FXのImageViewにコピーする。ファイル渡しで
   * コピーする。
   */
  public synchronized void setImage() {
  	long st = System.currentTimeMillis();

    vtkWindowToImageFilter w2if = new vtkWindowToImageFilter();
    canvas3D.lock();
    /**
     * 以下の行を入力すると、Widgetの操作が正常に行うことができる。
     * insert below line , then Widget controll is fine.
     */
    canvas3D.getRenderWindowInteractor().SetEnableRender(false);
    w2if.SetInput(canvas3D.GetRenderWindow());
    w2if.Update();
    canvas3D.unlock();

  	writer.SetInput(w2if.GetOutput());
    writer.SetFileName(tempFile.getPath());
    writer.Write();
    javafx.scene.image.Image img = new javafx.scene.image.Image(uri);
  	imageNode.setImage(img);

// 		imageNode.setImage(createWritableImage());
  	long en = System.currentTimeMillis();
  	long diff = en-st+10;
  	if(repaintInterval < diff) {
//  		System.out.println("Copy imege time="+(diff-10)+" msec");
  		repaintInterval = (int)diff;
  	} else {
    	repaintimer.setDelay(repaintInterval-=5);
//  		System.out.println("repaint interval ="+repaintInterval);
  	}
//  	System.out.println("setimageflag="+setimageflag);
  }
  /**
   * サイズの変更可能。
   */
  public boolean isResizable() {
  	return true;
  }
  /**
   * 描画領域の大きさを設定する。
   * @param width 幅
   * @param height 高さ
   */
  public void setSize(int width, int height) {
  	canvas3D.setSize(width, height);
  }
  /**
   * 描画領域のSwingオブジェクトを取得する。
   * @return vtkCanvas
   */
  public vtkCanvas getCanvas3D() {
  	return canvas3D;
  }
  /**
   * 再描画タイマーオブジェクトの取得
   * @return タイマーオブジェクト
   */
  public Timer getRepaintimer() {
		return repaintimer;
	}
  /**
   * 表示アクターの追加
   * @param actor 表示するアクター
   */
  public void addActor(vtkActor actor) {
  	canvas3D.GetRenderer().AddActor(actor);
  }
  /**
   * イメージノードの大きさをシーンに合わせます。タイマーを作成し
   * 起動します。このメソッドは、シーンを作成した後に実行します。
   * <p>
   * This method execute after scene created.
   * </p>
   */
  public void renderStart() {
  	imageNode.fitWidthProperty().bind(widthProperty());
  	imageNode.fitHeightProperty().bind(heightProperty());
    /*
     * イメージコピータイマーの定義
     */
    repaintimer = new Timer(repaintInterval, new ActionListener() {
    	@Override
    	public void actionPerformed(ActionEvent e) {
    		if(setimageflag == -1) {
    			setImage();
    			setimageflag = 1;
    			canvas3D.GetRenderer().ResetCamera();
    		} else if(setimageflag > 0) {
    			setImage();
    			setimageflag = 0;
      		SwingUtilities.invokeLater(() -> {
      			canvas3D.repaint();
//      			System.out.println("repaint");
      			});
    		}
    	}
    });
    repaintimer.setInitialDelay(800);
    repaintimer.start();

  }
  /**
   * 終了処理、タイマーの停止とイメージファイルの消去
   */
  public void finalize() {
  	try {
			super.finalize();
			repaintimer.stop();
			tempFile.delete();
			setimageflag = -1;
		} catch (Throwable e) {
			e.printStackTrace();
		}
  }
}





--
View this message in context: http://vtk.1045678.n5.nabble.com/VTK-and-JavaFX-tp5728083p5743332.html
Sent from the VTK - Users mailing list archive at Nabble.com.


More information about the vtkusers mailing list