17.5. Manipulators

You can use manipulators in your application in various ways:

  • You can use the replaceNode() method to replace certain kinds of nodes in the scene graph with an editable version. When the user is finished manipulating the node, use the replaceManip() method to restore the original node to the scene graph.

  • You can write your own callback functions to use the field values of the manipulator. The callback functions described in the section called “Callback Functions” can be used for any manipulator. (Recall that these functions belong to the dragger, so you need to call getDragger() before using them.)

You can also combine use of these two techniques. For example, you can use replaceNode() to replace an SoTransform SoTransform SoTransform 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.

Replacing a Node with a Manipulator

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 SoTransform SoTransform , such as the handle box and trackball, replace an SoTransform SoTransform SoTransform node. An SoDirectionalLight- Manip replaces an SoDirectionalLight SoDirectionalLight SoDirectionalLight node, an SoPointLightManip SoPointLightManip SoPointLightManip replaces an SoPointLight SoPointLight SoPointLight node, and so on.

Replacing a Node

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

replaceNode(SoPath *p)
  
ReplaceNode(SoPath p)
  
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 SoTransform SoTransform node. When a transform manipulator replaces this node, editing the manipulator will affect cube2 in the scene graph.

Manipulators subclassed from SoTransformManip SoTransformManip SoTransformManip 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.

Specifying the Path to the Target Node

Figure 17.8.  Specifying the Path to the Target Node



Removing the Manipulator

To remove the manipulator from the scene graph:

  1. Use the replaceManip() method to restore the original node to the scene graph. In the example, the field values from the manipulator are copied into the transform node.

  2. Use unref() on the manipulator so that it will be deleted.

Because the manipulator methods replaceManip() and replaceNode() exchange the new node for the tail of the given path, you can reuse the path for subsequent calls to these methods.

For example, if we begin with:

myManip = new SoTrackballManip;
myPathToTransform = createPathtoTransform(pickPath);
    
SoTrackballManip myManip = new SoTrackballManip();
SoPath myPathToTransform = createPathtoTransform(pickPath);
    
SoTrackballManip myManip = new SoTrackballManip();
SoPath myPathToTransform = createPathtoTransform(pickPath);
    

Then we can call:

myManip->replaceNode(myPathToTransform);
                          
myManip.ReplaceNode(myPathToTransform);
                          
myManip.replaceNode(myPathToTransform);
    

to put the manipulator at the end of the path.

Later, we can call

myManip->replaceManip(myPathToTransform, new SoTransform);
                          
myManip.ReplaceManip(myPathToTransform, new SoTransform());
                          
myManip.replaceManip(myPathToTransform, new SoTransform());

to remove the manipulator and replace it with a transform.

Using the replaceNode() Method

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 SoWrapperKit SoWrapperKit . 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:

  • Using replaceNode() and replaceManip() to make certain nodes in the scene graph editable and to restore the original nodes when manipulation finishes

  • Using selection callbacks (see Chapter 10, Handling Events and Selection)

    Example 17.3.  Using Manipulators to Transform Objects

    // Note that for illustration purposes, the
    // cube and SoWrapperKit already have transform nodes 
    // associated with them; the sphere does not. In all cases, 
    // the routine createTransformPath() is used to find the 
    // transform node that affects the picked object.
    
    #include <Inventor/SoDB.h>
    #include <Inventor/SoInput.h>
    #include <Inventor/manips/SoHandleBoxManip.h>
    #include <Inventor/manips/SoTrackballManip.h>
    #include <Inventor/manips/SoTransformBoxManip.h>
    #include <Inventor/nodekits/SoWrapperKit.h>
    #include <Inventor/nodes/SoCamera.h>
    #include <Inventor/nodes/SoCube.h>
    #include <Inventor/nodes/SoGroup.h>
    #include <Inventor/nodes/SoLight.h>
                                


    Adding Manipulators to a Scene

    Figure 17.9.  Adding Manipulators to a Scene



    #include <Inventor/nodes/SoMaterial.h>
    #include <Inventor/nodes/SoSelection.h>
    #include <Inventor/nodes/SoSphere.h>
    #include <Inventor/nodes/SoTransform.h>
    
    #include <Inventor/Xt/SoXt.h>
    #include <Inventor/Xt/viewers/SoXtExaminerViewer.h>
    
    // function prototypes
    void selectionCallback(void *, SoPath *);
    void deselectionCallback(void *, SoPath *);
    void dragStartCallback(void *, SoDragger *);
    void dragFinishCallback(void *, SoDragger *);
    
    // global data
    SoSeparator *root;
    SoHandleBoxManip    *myHandleBox;
    SoTrackballManip    *myTrackball;
    SoTransformBoxManip *myTransformBox;
    SoPath *handleBoxPath    = NULL;
    SoPath *trackballPath    = NULL;
    SoPath *transformBoxPath = NULL;
    
    main(int, char **argv)
    {
       // Initialize Inventor and Xt
       Widget myWindow = SoXt::init(argv[0]);
       if (myWindow == NULL) exit(1);
    
       // Create and set up the selection node
       SoSelection *selectionRoot = new SoSelection;
       selectionRoot->ref();
       selectionRoot->
          addSelectionCallback(selectionCallback, NULL);
       selectionRoot->
          addDeselectionCallback(deselectionCallback, NULL);
    
       // Create the scene graph
       root = new SoSeparator;
       selectionRoot->addChild(root);
    
       // Read a file into contents of SoWrapperKit 
       // Translate it to the right.
       SoWrapperKit *myWrapperKit = new SoWrapperKit;
       root->addChild(myWrapperKit);
       SoInput myInput;
       if (!myInput.openFile("luxo.iv")) 
          return (1);
       SoSeparator *objectFromFile = SoDB::readAll(&myInput);
       if (objectFromFile == NULL) return (1);
       myWrapperKit->setPart("contents",objectFromFile);
       myWrapperKit->set("transform { translation 3 -1 0 }");
       SoMaterial *wrapperMat 
          = (SoMaterial *) myWrapperKit->getPart("material",TRUE);
       wrapperMat->diffuseColor.setValue(.8, .8, .8);
    
       // Create a cube with its own transform.
       SoSeparator *cubeRoot = new SoSeparator;
       SoTransform *cubeXform = new SoTransform;
       cubeXform->translation.setValue(-4, 0, 0);
       root->addChild(cubeRoot);
       cubeRoot->addChild(cubeXform);
    
       SoMaterial *cubeMat = new SoMaterial;
       cubeMat->diffuseColor.setValue(.8, .8, .8);
       cubeRoot->addChild(cubeMat);
       cubeRoot->addChild(new SoCube);
    
       // Add a sphere node without a transform
       // (one will be added when we attach the manipulator)
       SoSeparator *sphereRoot = new SoSeparator;
       SoMaterial *sphereMat = new SoMaterial;
       root->addChild(sphereRoot);
       sphereRoot->addChild(sphereMat);
       sphereRoot->addChild(new SoSphere);
       sphereMat->diffuseColor.setValue(.8, .8, .8);
    
       // Create the manipulators
       myHandleBox = new SoHandleBoxManip;
       myHandleBox->ref();
       myTrackball = new SoTrackballManip;
       myTrackball->ref();
       myTransformBox = new SoTransformBoxManip;
       myTransformBox->ref();
    
       // Get the draggers and add callbacks to them. Note
       // that you don't put callbacks on manipulators. You put
       // them on the draggers which handle events for them. 
       SoDragger *myDragger;
       myDragger = myTrackball->getDragger();
       myDragger->addStartCallback(dragStartCallback,cubeMat);
       myDragger->addFinishCallback(dragFinishCallback,cubeMat);
    
       myDragger = myHandleBox->getDragger();
       myDragger->addStartCallback(dragStartCallback,sphereMat);
       myDragger->addFinishCallback(dragFinishCallback,sphereMat);
    
       myDragger = myTransformBox->getDragger();
       myDragger->addStartCallback(dragStartCallback,wrapperMat);
       myDragger->addFinishCallback(dragFinishCallback,wrapperMat);
    
       SoXtExaminerViewer *myViewer 
          = new SoXtExaminerViewer(myWindow);
       myViewer->setSceneGraph(selectionRoot);
       myViewer->setTitle("Attaching Manipulators");
       myViewer->show();
       myViewer->viewAll();
    
       SoXt::show(myWindow);
       SoXt::mainLoop();
    }
    
    // Is this node of a type that is influenced by transforms?
    SbBool
    isTransformable(SoNode *myNode)
    {
       if (myNode->isOfType(SoGroup::getClassTypeId())
          || myNode->isOfType(SoShape::getClassTypeId())
          || myNode->isOfType(SoCamera::getClassTypeId())
          || myNode->isOfType(SoLight::getClassTypeId()))
          return TRUE;
       else 
          return FALSE;
    }
    
    //  Create a path to the transform node that affects the tail
    //  of the input path.  Three possible cases:
    //   [1] The path-tail is a node kit. Just ask the node kit for
    //       a path to the part called "transform"
    //   [2] The path-tail is NOT a group.  Search siblings of path
    //       tail from right to left until you find a transform. If
    //       none is found, or if another transformable object is 
    //       found (shape,group,light,or camera), then insert a 
    //       transform just to the left of the tail. This way, the 
    //       manipulator only affects the selected object.
    //   [3] The path-tail IS a group.  Search its children left to
    //       right until a transform is found. If a transformable
    //       node is found first, insert a transform just left of 
    //       that node.  This way the manip will affect all nodes
    //       in the group.
    SoPath *
    createTransformPath(SoPath *inputPath)
    {
       int pathLength = inputPath->getLength();
       if (pathLength < 2) // Won't be able to get parent of tail
          return NULL;
    
       SoNode *tail = inputPath->getTail();
    
       // CASE 1: The tail is a node kit.
       // Nodekits have built in policy for creating parts.
       // The kit copies inputPath, then extends it past the 
       // kit all the way down to the transform. It creates the
       // transform if necessary.
       if (tail->isOfType(SoBaseKit::getClassTypeId())) {
          SoBaseKit *kit = (SoBaseKit *) tail;
          return kit->createPathToPart("transform",TRUE,inputPath);
       }
    
       SoTransform *editXf = NULL;
       SoGroup     *parent;
       SbBool      existedBefore = FALSE;
    
       // CASE 2: The tail is not a group.
       SbBool isTailGroup;
       isTailGroup = tail->isOfType(SoGroup::getClassTypeId());
       if (!isTailGroup) {
          // 'parent' is node above tail. Search under parent right
          // to left for a transform. If we find a 'movable' node
          // insert a transform just left of tail.  
          parent = (SoGroup *) inputPath->getNode(pathLength - 2);
          int tailIndx = parent->findChild(tail);
    
          for (int i = tailIndx; (i >= 0) && (editXf == NULL);i--){
             SoNode *myNode = parent->getChild(i);
             if (myNode->isOfType(SoTransform::getClassTypeId()))
                editXf = (SoTransform *) myNode;
             else if (i != tailIndx && (isTransformable(myNode)))
                break;
          }
          if (editXf == NULL) {
             existedBefore = FALSE;
             editXf = new SoTransform;
             parent->insertChild(editXf, tailIndx);
          }
          else
             existedBefore = TRUE;
       }
       // CASE 3: The tail is a group.
       else {
          // Search the children from left to right for transform 
          // nodes. Stop the search if we come to a movable node
          // and insert a transform before it.
          parent = (SoGroup *) tail;
          for (int i = 0;
             (i < parent->getNumChildren()) && (editXf == NULL); 
             i++) {
             SoNode *myNode = parent->getChild(i);
             if (myNode->isOfType(SoTransform::getClassTypeId()))
                editXf = (SoTransform *) myNode;
             else if (isTransformable(myNode))
                break;
          }
          if (editXf == NULL) {
             existedBefore = FALSE;
             editXf = new SoTransform;
             parent->insertChild(editXf, i);
          }
          else 
             existedBefore = TRUE;
       }
    
       // Create 'pathToXform.' Copy inputPath, then make last
       // node be editXf.
       SoPath *pathToXform = NULL;
       pathToXform = inputPath->copy();
       pathToXform->ref();
       if (!isTailGroup) // pop off the last entry.
          pathToXform->pop();
       // add editXf to the end
       int xfIndex   = parent->findChild(editXf);
       pathToXform->append(xfIndex);
       pathToXform->unrefNoDelete();
    
       return(pathToXform);
    }
    
    // This routine is called when an object
    // gets selected. We determine which object
    // was selected, then call replaceNode()
    // to replace the object's transform with
    // a manipulator.
    void
    selectionCallback(
       void *, // user data is not used
       SoPath *selectionPath)
    {
       // Attach the manipulator.
       // Use the convenience routine to get a path to
       // the transform that affects the selected object.
       SoPath *xformPath = createTransformPath(selectionPath);
       if (xformPath == NULL) return;
       xformPath->ref();
    
       // Attach the handle box to the sphere,
       // the trackball to the cube
       // or the transformBox to the wrapperKit
       if (selectionPath->getTail()->isOfType(
            SoSphere::getClassTypeId())) {
          handleBoxPath = xformPath;
          myHandleBox->replaceNode(xformPath);
       }
       else if (selectionPath->getTail()->
            isOfType(SoCube::getClassTypeId())) {
          trackballPath = xformPath;
          myTrackball->replaceNode(xformPath);
       }
       else if (selectionPath->getTail()->
            isOfType(SoWrapperKit::getClassTypeId())) {
          transformBoxPath = xformPath;
          myTransformBox->replaceNode(xformPath);
       }
    }
    
    // This routine is called whenever an object gets
    // deselected. It detaches the manipulator from
    // the transform node, and removes it from the 
    // scene graph that will not be visible.
    void
    deselectionCallback(
       void *, // user data is not used
       SoPath *deselectionPath)
    {
       if (deselectionPath->getTail()->
            isOfType(SoSphere::getClassTypeId())) {
          myHandleBox->replaceManip(handleBoxPath,NULL);
          handleBoxPath->unref();
       }
       else if (deselectionPath->getTail()->
            isOfType(SoCube::getClassTypeId())) {
          myTrackball->replaceManip(trackballPath,NULL);
          trackballPath->unref();
       }
       else if (deselectionPath->getTail()->
            isOfType(SoWrapperKit::getClassTypeId())) {
          myTransformBox->replaceManip(transformBoxPath,NULL);
          transformBoxPath->unref();
       }
    }
    
    // This is called when a manipulator is
    // about to begin manipulation.
    void
    dragStartCallback(
       void *myMaterial, // user data
       SoDragger *)         // callback data not used
    {
       ((SoMaterial *) myMaterial)->diffuseColor=SbColor(1,.2,.2);
    }
    
    // This is called when a manipulator is
    // done manipulating.
    void
    dragFinishCallback(
       void *myMaterial, // user data
       SoDragger *)    // callback data not used
    {
       ((SoMaterial *) myMaterial)->diffuseColor=SbColor(.8,.8,.8);
    }
        
                  
                
    package inventor.mentor.attachManip;
    
    import tools.*;
    
    import com.openinventor.inventor.nodes.*;
    import com.openinventor.inventor.manips.*;
    import com.openinventor.inventor.*;
    import com.openinventor.inventor.draggers.*;
    import com.openinventor.inventor.misc.callbacks.*;
    import com.openinventor.inventor.awt.*;
    
    import java.awt.*;
    
    public class Main extends DemoInventor
    {
      SoHandleBoxManip    myHandleBox      = new SoHandleBoxManip();
      SoTrackballManip    myTrackball      = new SoTrackballManip();
      SoTransformBoxManip myTransformBox   = new SoTransformBoxManip();
    
      SoPath              handleBoxPath    = null;
      SoPath              trackballPath    = null;
      SoPath              transformBoxPath = null;
    
      SoMaterial          cubeMat          = new SoMaterial();
      SoMaterial          sphereMat        = new SoMaterial();
      SoMaterial          coneMat          = new SoMaterial();
    
      public static void main(String[] args)
      {
        Main applet = new Main();
        DemoInventor.isAnApplet = false;
        applet.start();
        demoMain(applet, "Attaching Manipulators");
      }
    
      public void start()
      {
        super.start();
    
        // create and set up the selection node
        SoSelection selectionRoot = new SoSelection();
    
        // Create a cone
        SoSeparator coneRoot = new SoSeparator();
    
        SoTransform coneTrans = new SoTransform();
        coneTrans.translation.setValue(3, 0, 0);
        coneMat.diffuseColor.setValue(0.8f, 0.8f, 0.8f);
        {
          coneRoot.addChild(coneTrans);
          coneRoot.addChild(coneMat);
          coneRoot.addChild(new SoCone());
        }
    
        // Create a cube with its own transform.
        SoSeparator cubeRoot = new SoSeparator();
        SoTransform cubeXform = new SoTransform();
        cubeXform.translation.setValue(-3.0f, 0.0f, 0.0f);
        cubeMat.diffuseColor.setValue(0.8f, 0.8f, 0.8f);
        {
          cubeRoot.addChild(cubeXform);
          cubeRoot.addChild(cubeMat);
          cubeRoot.addChild(new SoCube());
        }
    
        // add a sphere node without a transform
        // (one will be added when we attach the manipulator)
        SoSeparator sphereRoot = new SoSeparator();
        sphereMat.diffuseColor.setValue(0.8f, 0.8f, 0.8f);
        {
          sphereRoot.addChild(sphereMat);
          sphereRoot.addChild(new SoSphere());
        }
    
        // create the scene graph
        SoSeparator root = new SoSeparator();
        { // assemble scene graph
          root.addChild(coneRoot);
          root.addChild(cubeRoot);
          root.addChild(sphereRoot);
        }
    
        // Get the draggers and add callbacks to them. Note
        // that you don't put callbacks on manipulators. You put
        // them on the draggers which handle events for them.
        SoDragger myDragger = myTrackball.getDragger();
        myDragger.addStartCallback(new DragStartCallback(cubeMat), null);
        myDragger.addFinishCallback(new DragFinishCallback(cubeMat), null);
    
        myDragger = myHandleBox.getDragger();
        myDragger.addStartCallback(new DragStartCallback(sphereMat), null);
        myDragger.addFinishCallback(new DragFinishCallback(sphereMat), null);
    
        myDragger = myTransformBox.getDragger();
        myDragger.addStartCallback(new DragStartCallback(coneMat), null);
        myDragger.addFinishCallback(new DragFinishCallback(coneMat), null);
    
        { // Assemble scene graph
          selectionRoot.addSelectionCallback(new SelectionCallback(), null);
          selectionRoot.addDeselectionCallback(new DeselectionCallback(), null);
          selectionRoot.addChild(root);
        }
    
        SwSimpleViewer myViewer = new SwSimpleViewer();
        myViewer.setSceneGraph(selectionRoot);
        setLayout(new BorderLayout());
        add(myViewer, BorderLayout.CENTER);
      }
    
      // Is this node of a type that is influenced by transforms?
      boolean isTransformable(SoNode myNode)
      {
        if (myNode instanceof SoGroup || myNode instanceof SoShape ||
            myNode instanceof SoCamera || myNode instanceof SoLight)
          return true;
        else
          return false;
      }
    
      SoPath createTransformPath(SoPath inputPath)
      {
        int pathLength = inputPath.regular.getLength();
        if (pathLength < 2) // Won't be able to get parent of tail
          return null;
    
        SoNode tail = inputPath.regular.getTail();
        /*
         * // CASE 1: The tail is a node kit. // Nodekits have built in policy for
         * creating parts. // The kit copies inputPath, then extends it past the //
         * kit all the way down to the transform. It creates the // transform if
         * necessary. if (tail instanceof SoBaseKit) { SoBaseKit kit =
         * (SoBaseKit)tail; return kit.createPathToPart("transform", true,
         * inputPath); }
         */
        SoTransform editXf = null;
        SoGroup parent;
        boolean existedBefore = false;
    
        // CASE 2: The tail is not a group.
        boolean isTailGroup;
        isTailGroup = tail instanceof SoGroup;
        if (!isTailGroup)
        {
          // 'parent' is node above tail. Search under parent right
          // to left for a transform. If we find a 'movable' node
          // insert a transform just left of tail.
          parent = (SoGroup) inputPath.regular.getNode(pathLength - 2);
          int tailIndx = parent.findChild(tail);
    
          for (int i = tailIndx; (i >= 0) && (editXf == null); i--)
          {
            SoNode myNode = parent.getChild(i);
            if (myNode instanceof SoTransform)
              editXf = (SoTransform) myNode;
            else if (i != tailIndx && (isTransformable(myNode)))
              break;
          }
          if (editXf == null)
          {
            existedBefore = false;
            editXf = new SoTransform();
            parent.insertChild(editXf, tailIndx);
          }
          else
            existedBefore = true;
        }
        // CASE 3: The tail is a group.
        else
        {
          // Search the children from left to right for transform
          // nodes. Stop the search if we come to a movable node.
          // and insert a transform before it.
          int i;
    
          parent = (SoGroup) tail;
          for (i = 0; (i < parent.getNumChildren()) && (editXf == null); i++)
          {
            SoNode myNode = parent.getChild(i);
            if (myNode instanceof SoTransform)
              editXf = (SoTransform) myNode;
            else if (isTransformable(myNode))
              break;
          }
          if (editXf == null)
          {
            existedBefore = false;
            editXf = new SoTransform();
            parent.insertChild(editXf, i);
          }
          else
            existedBefore = true;
        }
    
        // Create 'pathToXform.' Copy inputPath, then make last
        // node be editXf.
        SoPath pathToXform = null;
        pathToXform = inputPath.regular.copy(0);
    
        if (!isTailGroup) // pop off the last entry.
          pathToXform.regular.pop();
        // add editXf to the end
        int xfIndex = parent.findChild(editXf);
        pathToXform.regular.append(xfIndex);
    
        return (pathToXform);
      }
    
      class SelectionCallback extends SoSelectionPathCB
      {
        public void invoke(SoPath path)
        {
          // Attach the manipulator.
          // Use the convenience routine to get a path to
          // the transform that effects the selected object.
          SoPath xformPath = createTransformPath(path);
          if (xformPath == null)
            return;
    
          // Attach the handle box to the sphere,
          // the trackball to the cube
          // or the transformBox to the wrapperKit
          if (path.regular.getTail() instanceof SoSphere)
          {
            handleBoxPath = xformPath;
            myHandleBox.replaceNode(xformPath);
          }
          else if (path.regular.getTail() instanceof SoCube)
          {
            trackballPath = xformPath;
            myTrackball.replaceNode(xformPath);
          }
          else if (path.regular.getTail() instanceof SoCone)
          {
            transformBoxPath = xformPath;
            myTransformBox.replaceNode(xformPath);
          }
        }
      }
    
      class DeselectionCallback extends SoSelectionPathCB
      {
        public void invoke(SoPath path)
        {
          if (path.regular.getTail() instanceof SoSphere)
            myHandleBox.replaceManip(handleBoxPath, new SoTransform());
          else if (path.regular.getTail() instanceof SoCube)
            myTrackball.replaceManip(trackballPath, new SoTransform());
          else if (path.regular.getTail() instanceof SoCone)
            myTransformBox.replaceManip(transformBoxPath, new SoTransform());
        }
      }
    
      // This is called when a manipulator is
      // about to begin manipulation.
      class DragStartCallback extends SoDraggerCB
      {
        SoMaterial m_material;
    
        public DragStartCallback(SoMaterial mat)
        {
          m_material = mat;
        }
    
        public void invoke(SoDragger d)
        {
          m_material.diffuseColor.setValue(new SbColor(1.0f, 0.2f, 0.2f));
        }
      }
    
      // This is called when a manipulator is
      // done manipulating.
      class DragFinishCallback extends SoDraggerCB
      {
        SoMaterial m_material;
    
        public DragFinishCallback(SoMaterial mat)
        {
          m_material = mat;
        }
    
        public void invoke(SoDragger d)
        {
          m_material.diffuseColor.setValue(new SbColor(0.8f, 0.8f, 0.8f));
        }
      }
    }
      

Clip Plane Manipulator

Figure 17.10. Clip plane manipulation class



The SoClipPlaneManip SoClipPlaneManip SoClipPlaneManip manipulator was developed to allow easy interactive manipulation of the clipping plane (see SoClipPlane SoClipPlane SoClipPlane ). The SoClipPlaneManip SoClipPlaneManip SoClipPlaneManip utilizes an SoJackDragger SoJackDragger SoJackDragger to provide a 3D interface for moving the clip plane. This manipulator derives from SoClipPlane SoClipPlane SoClipPlane 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 SoClipPlaneManip SoClipPlaneManip at the center of the scene graph. The program source code is available in:

$OIVHOME/src/Inventor/examples/Features/

ClipPlaneManip/ClipPlaneManip.cxx.

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