ShapeViewer Plug-in Guide
Revised 8 September 2009
The LONI ShapeViewer, version 2.0, may now be extended using dynamically loaded plug-in modules.
This guide describes use and programming of these plug-in modules.
Table of Contents
About ShapeViewer Plug-ins
The LONI ShapeViewer's scene display capabilities can now be extended via externally supplied plug-in modules.
Plugin JAR files afford a means to add user-defined capabilites to the ShapeViewer 3D display.
These capabilities are
read-only and are do not modify the shape viewer's internal capabilities.
Within these limitations, a plug-in may add any display options afforded by the Java3D Java extension.
Using Shape Viewer plug-ins
The shape viewer provides a few plug-in capabilites by default. There are two ways to enable the viewer to load
plug-in's that are stored external to the viewer application:
- Enable plug-ins on the java command lne used to launch the viewer
- Load a single plugin file via the "Load Plug-Ins'" user menu item.
The first of these alternatives requres that the command line argument "-plugin" be added to the Java
command line used to start the viewer. If the viewer was started by double-clicking an icon in the computer,
this alternative is not available. If it is used, the
ShapeViewer will search the contents of a directory
for files whose names endi in the extension ".jar"; All Java JAR files so located will be searched for
ShapeViewer plug-in classes, and these classes will be loaded into the viewer. By default, this directory is
names "plugins" and must be a subdirectory of the directory containing the ShapeViewer application Jar file.
The location of this plugins directory may be changed by adding to the command line argument "pluginDirectory", followed
by the path to the directory. For example:
java -jar ShapeViewer.jar
will launch the shape viewer normally - it will not load plugin files.
java -jar ShapeViewer.jar -plugin
will add any plugin files in the "plugins" directory that is located in the same directory as the viewer.
java -jar ShapeViewer.jar -plugin -pluginDirectory /users/home/abc/myPlugins
will add any plugin files in the "myPlugins" directory, and ignore any other plugins.
A single plugin JAR file may be loaded at any time by use of the Extras menu item "Load Plug-In Jar".
Available Plug-in modules
- Axes
- Simple X, Y and Z coordiate axes may be displayed, as well as a simple bounding box.
- Sphere
- places a small sphere at the location of the last point picked by a user.
- MultiTracer
- The MultiTracer plug-in synchronized the ShapeViewer with MultiTracer. If a point is picked in the Viewer, MultiTracer will display the vertex location in an image volume.
Writing Shape Viewer Plug-Ins
Overview
ShapeViewer plug-ins extend what the viewer may do with the information represented by a displayed shape.
Plugin's are constrained by these policies:
-
- A Plug-in may read some current viewer state information (shape selected, point selected, bounding box).
- A Plug-in may not issue commnads to the viewer, or interact with other plug-ins
- A Plug-in may not change the Shape by the viewer.
Plug-in life cycle
- ) The plug-in is instantiated by the ShapeViewer.
- ) the plug-in's init() method is called by the viewer. The plugin will create any needed resources
- ) the plug-in's getPanel() method is called by the viewer, and the JPanel returned is added to the ShapeViewer display.
- ) the plug-ins getJava3D() method is called by the viewer to obtain a Java3D scene graph node which is added to the ShapeViewer java3d display. Changes made by the plug-in to this node, and it's children, are displayed to the user.
- a) The plug-in's update() method is called by the viewer to notify the plug-in that the viewer's state has changed. The plug-in may change it's GUI interface (the JPanel it supplied) or the java3d scene graph, or both, at any time.
- b) the plug-in's shapePicked() method is called by the viewer to notify the plug-in that the user has selected a java 3d vertex. The plug-in may change it's GUI interface (the JPanel it supplied) or the java3d scene graph, or both, at any time.
The ShapeViewerPlugin API
ShapeViewerPlugin API
Plug- In Class requirements
ShapeViewer plug-ins must follow these requirements:
- Plugin's must be written in java 1.5, and it's java .class files must be stored in a Java JAR file (the Java compiler used to create a plug-in must not be newer than the compiler used to build the ShapeViewer).
- A plugin must implement the Plugin interface
- Must implement a constructor that takes as it's sole argument an instance of an object implementing the IPluginCallback interface
- must have define a unique PluginID (duplicates PluginID's within a ShapeViewer are ignored)
- must provide a JPanel GUI
- must provide a string menu title for use in ShapeViewer GUI
- must put all Java3D
Plug-in Class Glossary
- Plugin
- The interface which a plug-in's entry point class must implement.
- PluginPartID
- an optional class that identifies a plugin component. This identifier is private to the plugin, and is used by the plug-support classes to provide some plug-in support methods.
- IPluginCallback
- Defines the interface that ShapeViewer plug-ins may call, to communicate with the ShapeViewer. Every plugin recieves a refer
- NoSuchPluginPartException
- thrown by the optional plug-in development support classes to indicate that a plugin component does not exist.
- PluginInfo
- A mandatory data structure that tells the ShapeViewer : the id of the plugin, the text used to select the plugin and the version string identifying the plug-in.
- PluginID
- A mandatory identifier used to distinguish a plug-in from other plug-ins.
- PickListener
- A class which a plug-in may use to select a point in the 3D scene. The selection process mimics the actions of a user's 'picking' the point with the mouse.
- Shape
- a ShapeTools shape. The purpose of the ShapeViewer is to display these Shapes.
- PluginImpl
- a simple implementation of a Plugin that provides default implementation of the interface. Generally, plug-ins will extend this class and overrided some or all of it's methods.
- Java3DPlugin
- an implmentation of the Plugin interface that provides useful java3d methods.
- SimpleJava3DPlugin
- an implmentation of the Plugin interface that allows a plug-in programmer to make simple 3D objects without having to learn Java3D.
Calls made by ShapeViewer to Plug-in(s)
This section describes how the ShapeViewer communicates with a plug-in.
- init()
- Initializes the plug-in. Called by the viewer after the Viewer has initialized itself. This method typically creates any plug-in GUI components, and any other needed initialization.
- close()
- releases any resources used by this plugin.
- update()
- notifes the plug-in that the state of the viewer has changed. These include changes to : the shapes displayed by the viewer, and to the currently selected viewer shape.
- getInfo()
- returns a PluginInfo class that describes the plug-in to the viewer.
- getJava3D()
- returns to the viewer the Java3D BranchGroup that is the sole parent to any 3D objects the plug-in wishes displayed in the viewer.
- shapePicked()
- Called when a user selects a shape vertex. This method supplies to the plug-in : the x and y screen coordinates of the location picked; the 3d location of picked vertex; the identifying label of the shape picked; and the index of the vertex selected (with respect to the shape containing that vertex).
- message()
- a text message that the plug-in may choose to display.
- command()
- a set of command line style arguments that the plug-in may respond to.
- addPickListener()
- registers a PickListener with the plug-in.
- removePickListener()
- removes a previosly registered PickListener from the plug-in.
Calls made by the plug-in to the Viewer
Plug-in's have access to:
- the Shape's that are displayed in the viewer.
- A small section of the viewer GUI display.
- The currently selected shape.
- The bounding box that contains all currently loaded viewer shape vertices.
- The 3D coordinates of a user's interactive selection of a shape vertex.
Plug-in Class Diagram
This is a simplified class diagram showing the support classes available to construct plug-ins.
It was last updated on 11 September 2009.

ShapeViewer Plugin Classes" width="631" height="603" />
Common Mistakes
Not initializing the PluginInfo
Every plug-in must supply to the ShapeViewer an instance of a PluginInfo. If this is not found, the viewer
will throw an IllegalStateException when it attempts to add the plug-in to the viewer. Typically, this is set
in the plug-in constructor.
Example:
public class PickReportPlugin extends AbstractSimplePlugin implements ActionListener
{
public PickReportPlugin(IPluginCallback pluginManager)
{
_pluginManager = pluginManager;
PluginID ID = new PluginID("PickReport v1.0");
// define PluginInfo for use by the viewer
_info = new PluginInfo(ID, "Pick Report", "1.0");
// use method supplied by PluginImpl to create Java3D branch group.
_branchGroup = getPluginRoot();
_panel = _initPanel(); // create GUI Panel for use by the ShapeViewer
}
// rest of plug-in code omitted in this example
}
Picking points from the Plug-In: Using a PickListener
ShapeViewer plug-ins may fire user point pick event. If done, this mimics the effect of a user selecting a point with the "Pick Points" options.
During the plug-in's installation, it's addPickListener(PickListener listener) is called by the PluginManager.
An interested plug-in may store this listener, and call it's pick() method to fire a user point pick event.
If done, the ShapeViewer will respond as if the user had used the mouse to "pick" the monitor screen location
intersecting a line drawn from the pick(x,y,z) vertex, and the java3d universe's idea of the location of the user's eye.
Note - for picking to work, the following two conditions must be true:
- ) Surface, or Surface Fill display mode must be enabled
- ) the "Pick Points" menu item must be enabled.
If either of these two conditions are not satisfied, the pick() call will be ignored.
Example
public class PickReportPlugin extends AbstractSimplePlugin implements ActionListener
{
/**
* Stores an object in the plug-in which may be called to
* pick a three dimensional location in the shape scene.
*
* Overrides the AbstractSimplePlugin's removePickListener method,
* which does nothing.
*
* @param listener an event listener that responds to 3d point selections by the plug-in.
*/
public void addPickListener(PickListener listener) {
_pickListener = listener;
}
/**
* Removes the pick listener.
* Overrides the AbstractSimplePlugin's removePickListener method,
* which does nothing.
*
* @param listener an event listener that responds to 3d point selections by the plug-in.
*/
public void removePickListener(PickListener listener) {
_pickListener = null;
}
/**
* Simulate a pick at the origin.
*/
public void pickOrigin()
{
_pickListener.pick(0,0,0);
}
}
Please note that embedding the PickListener's pick() method in the plug-ins's ShapePicked() method
will result in an infinite loop.
Plug-In Supporting Tools
AN SVN project with which to build a ShapeViewer plug-in
This SVN project enables a plug-in programmer to write ShapeViewer plug-ins with out needing ot have a copy
of the ShapeViewer source code. It contains:
- example plug-in classses.
- a stub (do-nothing) implementation of the IPluginCallback class, with with a plug-in may link, during development.
- an Ant build file to create the plug-in JAR file.
You can get this here: svn+ssh://svn.loni.ucla.edu/cvs/ccb/ShapeTools/ShapeViewerPlugin
SimpleJava3DPlugin class
Provides methods to allow simple graphics to be created and managed without requiring the programmer
to know Java3D. Complete methods API may be found
here.
This class uses the PluginPartID to keep track of various graphical components, within a plugin.
Some of it's methods, useful to the programmer who does not know Java3D, are:
- getPluginBranch()
- Gets the root of the plugin scene graph, creating it if needed. This is stored in the (inherited) field _branchRoot.
- addPolyLine(coordinates, rgbColors, lineID)
- creates a line from vertex coordinates and vertex rgbColors.
- updatePolyLine(lineID)
- redraws the line according to current values of the coordinates and rgbColors array values.
- removePolyLine(lineID)
- deletes the identified line.
- hasPluginPart(partID)
- determines if the plug-in has a part with the specifed part identifier.
- show()
- shows the plug-in Java3D scene in the ShapeViewer.
- hide()
- hides the plug-in Java3D scene in the ShapeViewer.
Plug-in Examples
A simple example;
This class displays an icon in the ShapeViewer plug-in
GUI. It has not other
interactions with the viewer.
package edu.ucla.loni.ccb.shapeviewer.plugin.impl;
import java.awt.Component;
import java.awt.Dimension;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import edu.ucla.loni.ccb.shapeviewer.ShapeViewerApplet;
import edu.ucla.loni.ccb.shapeviewer.plugin.IPluginCallback;
import edu.ucla.loni.ccb.shapeviewer.plugin.PluginInfo;
/**
* A default implementation of a Plug-in.
*
* @author Craig
*
* @version 28 August 2009
*/
public class IconPlugin extends PluginImpl
{
/** The unique identifier of this plug-in.*/
public static final String ID = "Default Plugin v1.0";
/**
* Creates an instance of the default plug-in.
*
* @param pluginManager class the coordinates communication between this plug-in and the ShapeViewer.
*/
public IconPlugin (IPluginCallback pluginManager)
{
super(pluginManager);
_info = new PluginInfo(ID, "Shape Viewer", "1.0");
_panel = _initPanel();
}
/**
* Gets the PluginInfo instance that describes this plug-in.
*
* @return a description of this plug-in.
*/
public PluginInfo getInfo()
{
return _info;
}
/**
* Gets the instance of the GUI panel associated with this plug-in, or null.
*
* @return this plug-ins user panel, or null if none exists.
*/
public JPanel getPanel() {
return _panel;
}
/**
* Create the GUI Panel used by this plug-in.
*
* @return a small GUI Panel used by this plug-in.
*/
private JPanel _initPanel()
{
JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
// create centered icon
ImageIcon image = _pluginManager.getShapeToolsIcon();
JLabel imageLabel;
if (image != null) {
imageLabel = new JLabel(image);
imageLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
} else {
imageLabel = new JLabel("ShapeViewer Version " + ShapeViewerApplet.VERSION);
}
panel.add(Box.createRigidArea(new Dimension(0,10)));
panel.add(imageLabel);
return panel;
}
}
An example using the SimpleJava3DPlugin?
This plug-in displays a poly line that connects three vertices.
The coordinates and colors of the vertices are randomly chosen, within the
range of -1 to +1.
package edu.ucla.loni.ccb.shapeviewer.plugin.impl;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import edu.ucla.loni.ccb.shapeviewer.plugin.DuplicatePluginPartException;
import edu.ucla.loni.ccb.shapeviewer.plugin.IPluginCallback;
import edu.ucla.loni.ccb.shapeviewer.plugin.Plugin;
import edu.ucla.loni.ccb.shapeviewer.plugin.PluginID;
import edu.ucla.loni.ccb.shapeviewer.plugin.PluginInfo;
import edu.ucla.loni.ccb.shapeviewer.plugin.PluginPartID;
/**
* This plug-in displays a PolyLine that connects three vertices.
* The coordinates and colors of the vertices are randomly chosen, within the
* range of -1 to +1.
*
* @author craig
*
* @version 11 September 2009
*/
public class RandomLine extends SimpleJava3DPlugin implements ActionListener, Plugin
{
/** string command associated with the visibility check box.*/
public static final String TOGGLE = "ToggleVisibilty";
/** string command associated with the update coordinates button .*/
public static final String UPDATE = "UpdateCoordinates";
/** The unique identifier of this plug-in.*/
public static final PluginID ID = new PluginID("RandomLine");
/** The GUI panel .*/
private JPanel _guiPanel;
/** the check box controlling whether Plug-in geometry is visible, or not.*/
private JCheckBox _visible;
/** the button that causes coordinates and colors to be randomized .*/
private JButton _randomize;
/** the (x,y,z) tuples of the line vertices.*/
private float [] _coords;
/** the (r,g,b) tuples of the line vertex colors.*/
private float [] _colors;
/** provides random floats for coordinates and colors.*/
private Random _randomNumberGenerator = new Random();
private PluginPartID _polylineID ;
/**
* Creates a Axes plug-in whose sphere is not displayed until the "Visible" check button is selected.
*
* @param plug-in manages communications between this plug-in and the rest of the application.
*/
public RandomLine (IPluginCallback pluginManager)
{
_pluginManager = pluginManager;
_guiPanel = _initPanel();
_info = new PluginInfo(ID, "RandomLine", "1.0");
_createPolyLine();
}
/**
* Gets the GUI panel that controls the Axes plug-in.
*
* @return a GUI Panel.
*/
public JPanel getPanel()
{
return _guiPanel;
}
/**
* Randomly changes line coordinates and colors.
*/
public void randomize()
{
for (int i=0;i<_coords.length;i++) {
// generate new coord between 0 and 1, randomly assign sign.
float f = _randomNumberGenerator.nextFloat();
if (_randomNumberGenerator.nextBoolean()) f = -f;
_coords[i] = f;
_colors[i] = _randomNumberGenerator.nextFloat();
}
}
/**
* Respond to check box and other actions of this plugin's GUI
*
* @param e a GUI action event.
*/
public void actionPerformed(ActionEvent e)
{
String actionCommand = e.getActionCommand();
if (actionCommand.equals(TOGGLE)) {
// button state changes first, then this
// method is run.
if (_visible.isSelected()) {
show();
} else {
hide();
}
} else if (actionCommand.equals(UPDATE)) {
_pluginManager.debug("update");
randomize();
if (_visible.isSelected()) {
// force java3d coordinate update by detaching and attaching branch group
hide(); show();
}
}
}
/**
* Create the User GUI panel for the this plug-in.
*
* @return a plug-in GUI panel;
*/
private JPanel _initPanel()
{
JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel,BoxLayout.Y_AXIS));
panel.setBounds(0, 0, 150, 150);
JLabel title = new JLabel("SimpleJava3D Plugin");
panel.add(title);
_visible = new JCheckBox("Show Lines", false);
_visible.setSelected(true);
_visible.addActionListener(this);
_visible.setActionCommand(TOGGLE);
_randomize = new JButton("Randomize Coordinates");
_randomize.addActionListener(this);
_randomize.setActionCommand(UPDATE);
panel.add(_visible);
panel.add(_randomize);
return panel;
}
/**
* Creates Java3D PolyLine
*/
private void _createPolyLine()
{
// create id for poly line
_polylineID = new PluginPartID("PolyLine");
// create vertex coordinate and color arrays
int numCoords =3 *3;
_coords = new float[numCoords];
_colors = new float[numCoords];
randomize();
try {
addPolyLine(_coords, _colors, _polylineID);
} catch (DuplicatePluginPartException dppe) {
_pluginManager.error(dppe.getLocalizedMessage());
}
}
}
See Also