package vtk.sample; import java.awt.BorderLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.lang.reflect.InvocationTargetException; import java.util.concurrent.Callable; import java.util.concurrent.CompletionService; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorCompletionService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.JCheckBox; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.SwingUtilities; import javax.swing.Timer; import vtk.vtkActor; import vtk.vtkDataSetMapper; import vtk.vtkNativeLibrary; import vtk.vtkObject; import vtk.vtkPanel; import vtk.vtkReferenceInformation; import vtk.vtkRenderer; import vtk.vtkShrinkFilter; import vtk.vtkSphereSource; /** * This application run concurrently thread that create VTK objects and the EDT * that collect those objects and render them. * * @author sebastien jourdain - sebastien.jourdain@kitware.com */ public class Demo extends JPanel { private static final long serialVersionUID = 1L; private vtkPanel panel3d; private JCheckBox runGC; private JCheckBox debugMode; private JLabel gcStatus; private int NUMBER_OF_PIPLINE_TO_BUILD = 120; private int nbSeconds; private final CompletionService exec; // ----------------------------------------------------------------- // 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); } // ----------------------------------------------------------------- public static class AddActorRunnable implements Runnable { private vtkActor actorToAdd; private vtkRenderer renderer; private vtkPanel panel; void setRenderer(vtkPanel panel) { this.renderer = panel.GetRenderer(); this.panel = panel; } void setActor(vtkActor a) { this.actorToAdd = a; } public void run() { this.renderer.AddActor(this.actorToAdd); this.panel.Render(); } } // ----------------------------------------------------------------- public static class PipelineBuilder implements Callable { private vtkActor actor; private vtkDataSetMapper mapper; private vtkShrinkFilter shrink; private vtkSphereSource sphere; public vtkActor call() throws Exception { // New actor = new vtkActor(); mapper = new vtkDataSetMapper(); shrink = new vtkShrinkFilter(); sphere = new vtkSphereSource(); // Settings sphere.SetPhiResolution(60); sphere.SetThetaResolution(60); double[] center = new double[3]; sphere.SetCenter(GetRandomCenter(center)); actor.GetProperty().SetColor(Math.random(), Math.random(), Math.random()); // Binding actor.SetMapper(mapper); mapper.SetInputConnection(shrink.GetOutputPort()); shrink.SetInputConnection(sphere.GetOutputPort()); // Update mapper.Update(); // Wait some time Thread.sleep((long) (Math.random() * 500)); // Return return actor; } public double[] GetRandomCenter(double[] center) { for (int i = 0; i < 3; i++) { center[i] = Math.random() * 10; } return center; } } // ----------------------------------------------------------------- public Demo() { super(new BorderLayout()); panel3d = new vtkPanel(); gcStatus = new JLabel(""); runGC = new JCheckBox("Enable GC", false); debugMode = new JCheckBox("Debug mode", false); exec = new ExecutorCompletionService(Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors())); // Setup UI JPanel statusBar = new JPanel(); statusBar.setLayout(new BoxLayout(statusBar, BoxLayout.X_AXIS)); statusBar.add(runGC); statusBar.add(debugMode); statusBar.add(Box.createHorizontalGlue()); statusBar.add(gcStatus); add(panel3d, BorderLayout.CENTER); add(statusBar, BorderLayout.SOUTH); // Init app // this.setupGC(); // We use a Swing timer that show the result in UI // instead.. this.setupWorkers(); // Update GC info into the UI every seconds // Reset camera each seconds the first 10 ones this.nbSeconds = 0; new Timer(1000, new ActionListener() { public void actionPerformed(ActionEvent e) { if (nbSeconds++ < 10) { panel3d.resetCamera(); } vtkRenderer renderer = panel3d.GetRenderer(); if (renderer.GetNumberOfPropsRendered() > 1) { renderer.RemoveActor(renderer.GetActors().GetLastProp()); } // Run GC in local thread (EDT) if (runGC.isSelected()) { vtkReferenceInformation info = vtkObject.JAVA_OBJECT_MANAGER.gc(debugMode.isSelected()); if (debugMode.isSelected()) { System.out.println(info.listKeptReferenceToString()); System.out.println(info.listRemovedReferenceToString()); } gcStatus.setText(info.toString()); } else { gcStatus.setText(""); } panel3d.Render(); } }).start(); } private void setupGC() { // Setup GC to run every 1 second in EDT vtkObject.JAVA_OBJECT_MANAGER.getAutoGarbageCollector().SetScheduleTime(1, TimeUnit.SECONDS); // Start/Stop the GC based on the checkbox runGC.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { vtkObject.JAVA_OBJECT_MANAGER.getAutoGarbageCollector().SetAutoGarbageCollection(runGC.isSelected()); } }); // Change GC mode based on the checkbox debugMode.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { vtkObject.JAVA_OBJECT_MANAGER.getAutoGarbageCollector().SetDebug(debugMode.isSelected()); } }); } private void setupWorkers() { // Add actor thread: Consume the working queue and add the actor into // the render inside the EDT thread final AddActorRunnable adderRunnable = new AddActorRunnable(); adderRunnable.setRenderer(panel3d); new Thread() { public void run() { for (int i = 0; i < NUMBER_OF_PIPLINE_TO_BUILD; i++) { try { adderRunnable.setActor(exec.take().get()); SwingUtilities.invokeAndWait(adderRunnable); panel3d.repaint(); } catch (InterruptedException e) { return; } catch (ExecutionException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } }; }.start(); } public void startWorking() { for (int i = 0; i < NUMBER_OF_PIPLINE_TO_BUILD; i++) { exec.submit(new PipelineBuilder()); } } // ----------------------------------------------------------------- public static void main(String[] args) throws InterruptedException, InvocationTargetException { SwingUtilities.invokeLater(new Runnable() { public void run() { Demo app = new Demo(); JFrame f = new JFrame("Concurrency test"); f.getContentPane().setLayout(new BorderLayout()); f.getContentPane().add(app, BorderLayout.CENTER); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.setSize(400, 400); f.setVisible(true); f.validate(); app.startWorking(); } }); } }