17.5. Manipulators

You can use manipulators in your application in various ways:

You can also combine use of these two techniques. For example, you can use replaceNode() to replace an SoTransform( C++ | Java | .NET ) with a manipulator. Then you can use a value-changed callback to notify the application when any of the manipulator's dragger fields changes, and the application can use this new value, if desired.

The following sections describe both of these techniques in more detail.

To use any manipulator in an application, follow these basic steps:

  1. Construct the manipulator.

  2. Reference it if you plan on reusing it.

  3. Replace the node in the scene graph with the manipulator. Manipulators derived from SoTransform( C++ | Java | .NET ), such as the handle box and trackball, replace an SoTransform( C++ | Java | .NET ) node. An SoDirectionalLight- Manip replaces an SoDirectionalLight( C++ | Java | .NET ) node, an SoPointLightManip( C++ | Java | .NET ) replaces an SoPointLight( C++ | Java | .NET ) node, and so on.

The replaceNode() method takes a path as an argument:


C++
replaceNode(SoPath *p)
  

.NET
ReplaceNode(SoPath p)
  

Java
replaceNode(SoPath p)
  

The path is supplied by the application. For example, Figure 17.8, “ Specifying the Path to the Target Node shows the path to a target SoTransform( C++ | Java | .NET ) node. When a transform manipulator replaces this node, editing the manipulator will affect cube2 in the scene graph.

Manipulators subclassed from SoTransformManip( C++ | Java | .NET ) use special nodes to maintain their shape (so that the trackball remains spherical, for example) and to ensure that they surround the shape objects they affect. These nodes are described in The Inventor Toolmaker.


Example 17.3, “ Using Manipulators to Transform Objects ” displays a cube, a sphere, and a lamp. The lamp is read from a file and inserted as the “contents” part of an SoWrapperKit( C++ | Java | .NET ). When the user picks the cube, a trackball replaces the transform node that affects the cube. When the user picks the sphere, a handle box replaces the transform node that affects the sphere. When the user picks the lamp, a transform box replaces the “transform” part of the wrapper kit containing the lamp. Figure 17.9, “ Adding Manipulators to a Scene shows an image created by this program. This example shows the following techniques:

Figure 17.10. Clip plane manipulation class


The SoClipPlaneManip( C++ | Java | .NET )manipulator was developed to allow easy interactive manipulation of the clipping plane (see SoClipPlane( C++ | Java | .NET ) ). The SoClipPlaneManip( C++ | Java | .NET )utilizes an SoJackDragger( C++ | Java | .NET )to provide a 3D interface for moving the clip plane. This manipulator derives from SoClipPlane( C++ | Java | .NET ) and maintains, like all other manipulators, consistency between the fields of the dragger and its own fields. Please read Chapter 17, Draggers and Manipulators of The Inventor Mentor for more information about manipulators.

Example 17.4.  How to use SoClipPlaneManip

This example reads an Inventor file and displays an SoClipPlaneManip( C++ | Java | .NET ) at the center of the scene graph. The program source code is available in:

$OIVHOME/src/Inventor/examples/Features/

ClipPlaneManip/ClipPlaneManip.cxx.


C++
int
main(int argc, char **argv)
{
  // Initialize Inventor and Xt
  Widget myWindow = SoXt::init(argv[0]);
  
  const char *filename = "../../../../data/models/slotMachine.iv";
  if (argc < 2)
    printf("Usage : %s <file.iv>\n", argv[0]);
  if (argc >=2)
    filename = argv[1];
  
  // Read the file
  SoSeparator *scene = readFile(filename);
  scene->ref();
  
  // Compute the bounding box of the scene graph.
  SoGetBoundingBoxAction bboxAction(SbViewportRegion(100, 100));
  bboxAction.apply(scene);
  // Inserting the manipulator at the center of the scene graph
  // and in the plane YZ.
  SoClipPlaneManip *clipPlaneManip = new SoClipPlaneManip;
  clipPlaneManip->setValue(bboxAction.getBoundingBox(),SbVec3f(1, 0, 0), 0.1);
  scene->insertChild(clipPlaneManip, 0);
  
  // Create a viewer
  SoXtExaminerViewer *myViewer = new SoXtExaminerViewer(myWindow);
  
  // Attach and show viewer
  myViewer->setSceneGraph(scene);
  myViewer->setTitle("File Reader");
  myViewer->show();
  
  // Loop forever
  SoXt::show(myWindow);
  SoXt::mainLoop();
  return 0;
}
         

.NET
string filename = "$OIVNETHOME/data/models/slotMachine.iv";
string[] args = Environment.GetCommandLineArgs();

if (args.Length < 2)
  Console.WriteLine("Usage : {0} <file.iv>\n", Application.ExecutablePath);

if (args.Length >= 2)
  filename = args[1];

// Read the file
SoSeparator scene = ReadFile(filename);

// Compute the bounding box of the scene graph.
SoGetBoundingBoxAction bboxAction = 
    new SoGetBoundingBoxAction(new SbViewportRegion(100, 100));
bboxAction.Apply(scene);

// Inserting the manipulator at the center of the scene graph and in the plane YZ.
SoClipPlaneManip clipPlaneManip = new SoClipPlaneManip();
clipPlaneManip.SetValue(bboxAction.GetBoundingBox(), new SbVec3f(1, 0, 0), 0.1f);
scene.InsertChild(clipPlaneManip, 0);

// Create a viewer
SoWinExaminerViewer myViewer = new SoWinExaminerViewer(this, "", true, 
          SoWinFullViewer.BuildFlags.BUILD_ALL, SoWinViewer.Types.BROWSER);

// attach and show viewer
myViewer.SetSceneGraph(scene);
myViewer.SetTitle("Clip Plane Manipulator");
myViewer.Show();
        

Java
public void start()
{
  super.start();
  setLayout(new BorderLayout());
  Panel panel = new Panel(new BorderLayout());

  myViewer = new SwSimpleViewer(SwSimpleViewer.EXAMINER);

  String filename = "../../../../data/models/slotMachine.iv";

  if (args.length < 1)
    System.out.println("Use arg <file.iv>\n");

  if (args.length >= 1)
    filename = args[0];

  // Read the file
  SoSeparator scene = readFile(filename);

  // Compute the bounding box of the scene graph.
  SoGetBoundingBoxAction bboxAction = 
      new SoGetBoundingBoxAction(new SbViewportRegion((short)100, (short)100));
  bboxAction.apply(scene);

  // Inserting the manipulator at the center of the scene graph and in the plane YZ.
  SoClipPlaneManip clipPlaneManip = new SoClipPlaneManip();
  clipPlaneManip.setValue(bboxAction.getBoundingBox(), new SbVec3f(1, 0, 0), 0.1f);
  scene.insertChild(clipPlaneManip, 0);

  // Create a viewer
  myViewer = new SwSimpleViewer(SwSimpleViewer.EXAMINER);
  // attach and show viewer
  myViewer.setSceneGraph(scene);

  panel.add(myViewer);
  add(panel);
}