15.11. Gate Engine

This section discusses the gateengine, which provides a convenient mechanism for selectively copying values from input to output. It also introduces the enable field and the trigger field, used by other engines.

By default, each time a value in an engine network changes, the new value propagates through the network. If a value is constantly changing, however, you may not want this change to propagate continuously through the scene graph. In this case, you might want to sample the value at regular intervals, or update the value only when a certain event occurs. Use the gate engine to control when such values are sent to the rest of the scene graph.

When you construct the gate engine, you pass in the type of its input and output fields. This type must be the type of a multiple-value field. (If you want to gate a single-value field, just pass in the corresponding multiple- value type and Inventor will automatically convert it.) Other engines with similar constructors are SoSelectOne SoSelectOne SoSelectOne and SoConcatenate SoConcatenate SoConcatenate .

SoGate SoGate SoGate has these two inputs:

enable (SoSFBool)

allows continuous flow of updated values

trigger (SoSFTrigger)

copies a single value

When the enable field is TRUE, data is allowed to be copied to the engine output each time a new value is received as input. To send only one value to the engine output, set the enable field to FALSE and use the trigger field to send the value. When the trigger field is touched, one value is sent. The trigger field is touched by calling either touch() or setValue() on it. Example 15.4, “ Using a Gate Engine ” connects an elapsed time engine (myCounter) to a gate engine (myGate). Pressing the mouse button enables and disables the gate engine, which in turn controls the motion of a duck in the scene. The scene graph for this example is shown in Figure 15.13, “ Scene Graph for Gate Engine Example.

Scene Graph for Gate Engine Example

Figure 15.13.  Scene Graph for Gate Engine Example



Example 15.4.  Using a Gate Engine

// Duck group
SoSeparator *duck = new SoSeparator;
root->addChild(duck);

// Read the duck object from a file and add to the group
SoInput myInput;
if (!myInput.openFile("duck.iv")) 
   return (1);
SoSeparator *duckObject = SoDB::readAll(&myInput);
if (duckObject == NULL) 
   return (1);

// Set up the duck transformations
SoRotationXYZ *duckRotXYZ = new SoRotationXYZ;
duck->addChild(duckRotXYZ);
SoTransform *initialTransform = new SoTransform;
initialTransform->translation.setValue(0., 0., 3.);
initialTransform->scaleFactor.setValue(6., 6., 6.);
duck->addChild(initialTransform);

duck->addChild(duckObject);

// Update the rotation value if the gate is enabled.
SoGate *myGate = new SoGate(SoMFFloat::getClassTypeId());
SoElapsedTime *myCounter = new SoElapsedTime;
myGate->input->connectFrom(&myCounter->timeOut); 
duckRotXYZ->axis = SoRotationXYZ::Y;  // rotate about Y axis
duckRotXYZ->angle.connectFrom(myGate->output);

// Add an event callback to catch mouse button presses.
// Each button press will enable or disable the duck motion.
SoEventCallback *myEventCB = new SoEventCallback;
myEventCB->addEventCallback(
         SoMouseButtonEvent::getClassTypeId(),
         myMousePressCB, myGate);
root->addChild(myEventCB);

...

// This routine is called for every mouse button event.
void
myMousePressCB(void *userData, SoEventCallback *eventCB)
{
   SoGate *gate = (SoGate *) userData;
   const SoEvent *event = eventCB->getEvent();
   // Check for mouse button being pressed
   if (SO_MOUSE_PRESS_EVENT(event, ANY)) {

      // Toggle the gate that controls the duck motion
      if (gate->enable.getValue()) 
         gate->enable.setValue(FALSE);
      else 
         gate->enable.setValue(TRUE);

      eventCB->setHandled();
   } 
}
    
// Duck group
SoSeparator duck = new SoSeparator();
root.AddChild(duck);

// Read the duck object from a file and add to the group
SoInput myInput = new SoInput();
myInput.OpenFile("../../../../../data/duck.iv");

SoSeparator duckObject = SoDB.ReadAll(myInput);

// Set up the duck transformations
SoRotationXYZ duckRotXYZ = new SoRotationXYZ();
duck.AddChild(duckRotXYZ);
SoTransform initialTransform = new SoTransform();
initialTransform.translation.SetValue(0.0f, 0.0f, 3.0f);
initialTransform.scaleFactor.SetValue(6.0f, 6.0f, 6.0f);
duck.AddChild(initialTransform);

duck.AddChild(duckObject);

// Update the rotation value if the gate is enabled.
myGate = new SoGate(typeof(SoMFFloat));
SoElapsedTime myCounter = new SoElapsedTime();
myGate.input.ConnectFrom(myCounter.timeOut); 
duckRotXYZ.axis.Value = SoRotationXYZ.AxisType.Y;  // rotate about Y axis
duckRotXYZ.angle.ConnectFrom(myGate.output);

// Add an event callback to catch mouse button presses.
// Each button press will enable or disable the duck motion.
SoEventCallback myEventCB = new SoEventCallback();
myEventCB.AddEventCallback(typeof(SoMouseButtonEvent), myMousePressCB);
root.AddChild(myEventCB);
  
// Duck group
SoSeparator duck = new SoSeparator();

// Read the duck object from a file and add to the group
SoInput myInput = new SoInput();
String filename = "../../../../data/models/duck.iv";

if (!myInput.openFile(m_prefix+filename)) {
  System.err.println("Cannot open file " + filename);
  System.exit(1);
}
SoSeparator duckObject = SoDB.readAll(myInput);
if (duckObject == null) {
  System.err.println("Cannot read file " + filename);
  System.exit(1);
}

// Set up the duck transformations
SoRotationXYZ duckRotXYZ = new SoRotationXYZ();
SoTransform initialTransform = new SoTransform();
initialTransform.translation.setValue(0.0f, 0.0f, 3.0f);
initialTransform.scaleFactor.setValue(6.0f, 6.0f, 6.0f);
{
  duck.addChild(duckRotXYZ);
  duck.addChild(initialTransform);
  duck.addChild(duckObject);
}

// Update the rotation value if the gate is enabled.
SoGate myGate = new SoGate(SoMFFloat.class);
SoElapsedTime myCounter = new SoElapsedTime();
myGate.input.connectFrom(myCounter.timeOut);
duckRotXYZ.axis.setValue(SoRotationXYZ.AxisType.Y);  // rotate about Y axis
duckRotXYZ.angle.connectFrom(myGate.output);

// Add an event callback to catch mouse button presses.
// Each button press will enable or disable the duck motion.
SoEventCallback myEventCB = new SoEventCallback();
myEventCB.addEventCallback(SoMouseButtonEvent.class,
                           new MousePressCB(myGate));