[vtkusers] Java multi-thread and model Observer

Jean-Max Redonnet jmax.red at gmail.com
Thu Feb 21 04:19:17 EST 2019


Hello everyone !

I'm using vtk throught its java wrapper and I'm setting up a versatile
viewer that can display an existing model and update display when this
model is updated (and it will be continously updated).

My Model is built around few classes: VtkObject that is the ancestor of
many other classes like VtkSurface, VtkCurve, etc... and VtkModel that
basically contains a list of VtkObjects and maintain Listeners. All these
classes are of my own (please note uppercase "V" on VtkObject)


public class VtkObject{
    protected final PropertyChangeSupport pcs = new
PropertyChangeSupport(this);
    protected List<vtkActor> actors = new ArrayList<vtkActor>();
    ...
}

public class VtkSurface extends VtkObject {
    private vtkActor surfActor;
    ...
}

public class VtkModel implements PropertyChangeListener{
    protected List<VtkObject> objects;
    protected PropertyChangeSupport support;
    ...
}

For the viewer itself I wrote a VtkPanel that is mostly inspired by the
example provided by Sébastien Jourdain (
https://github.com/Kitware/VTK/blob/master/Wrapping/Java/vtk/sample/Demo.java
)

I just make this panel model-aware implementing PropertyChangeListener:

    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        if (evt.getPropertyName() == "AddedObject") {
            System.out.println("Added Object");
            VtkObject o = (VtkObject) evt.getNewValue();
            if(o.getActors().size()>0)
                exec.submit(new PipelineBuilder(o));
        }
        if (evt.getPropertyName() == "UpdatedObject") {
            System.out.println("Updated Object");
            VtkObject o = (VtkObject) evt.getNewValue();
            if(o.getActors().size()>0)
                exec.submit(new PipelineBuilder(o));
        }
    }

and slithly modify PipelineBuilder to make it able to manage VtkObjects
that may contain several vtkActors

    public class PipelineBuilder implements Callable<vtkActor> {
        private int counter;
        private List<vtkActor> actors;

        public PipelineBuilder(VtkObject o) {
            actors = o.getActors();
            counter = 0;
        }

        @Override
        public vtkActor call() throws Exception {
            counter++;
            if (counter < actors.size() + 1)
                return actors.get(counter - 1);
            return null;
        }
    }

Also, workers are setup to continously search for new actors:

    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() {
                while (true) {
                    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();
    }


Here is the test class I use:

public class TestVtkPanel {
    public VtkModel model;

    public TestVtkPanel() {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                model = getModel();
                VtkPanel panel = new VtkPanel();
                model.addPropertyChangeListener(panel);

                JButton exitBtn = new JButton("Quitter");
                exitBtn.addActionListener(new ActionListener() {

                    public void actionPerformed(ActionEvent e) {
                        System.exit(0);
                    }
                });
                JFrame f = new JFrame("Vtk Viewer");
                f.getContentPane().setLayout(new BorderLayout());
                f.getContentPane().add(panel, BorderLayout.CENTER);
                f.getContentPane().add(exitBtn, BorderLayout.SOUTH);

                f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                f.setSize(800, 600);
                f.setVisible(true);
                f.validate();

                panel.startWorking(model);

                new Thread(new Runnable() {
                    public void run() {
                        updateModel();
                    }
                }).start();

            }
        });

    }


    ...
  }



All this stuff works fine, but few questions remains.

Is this way to do thing is the best for what I'm trying to achieve ? If a
vtk guru can give a look to my code, it would be gratefully appreciated.
Furthermore inside the VtkPanel constructor I tried to put the vtkPanel
panel3d outside of the Timer but that do not work.

    new Timer(1000, new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                if (nbSeconds++ < 1) {
                    panel3d.resetCamera();
                }
                // Run GC in local thread (EDT)
            ...
     }

I can't figure out why. Any hint on this point may help me to understand
multithreading.

Thanks for your help.

jMax
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://vtk.org/pipermail/vtkusers/attachments/20190221/8b50e039/attachment.html>


More information about the vtkusers mailing list