Exemplo n.º 1
0
/*!
 This implements typical action traversal for an SoComplexShape node
*/
void
SoComplexShape::doAction(SoAction *action)
{
  // Make sure all the children exist
  if (children->getLength() == 0) { generateChildren(); }

  // SoAction has a method called "getPathCode()" that returns
  // a code indicating how this node is related to the path(s)
  // the action is being applied to. This code is one of the
  // following:
  //
  // NO_PATH    = Not traversing a path (action was applied
  //                to a node)
  // IN_PATH    = This node is in the path chain, but is not
  //                the tail node
  // BELOW_PATH = This node is the tail of the path chain or
  //                is below the tail
  // OFF_PATH   = This node is off to the left of some node in
  //                the path chain
  //
  // If getPathCode() returns IN_PATH, it returns (in its two
  // arguments) the indices of the next nodes in the paths.
  // (Remember that an action can be applied to a list of
  // paths.)

  // For the IN_PATH case, these will be set by getPathCode()
  // to contain the number of child nodes that are in paths and
  // the indices of those children, respectively. In the other
  // cases, they are not meaningful.
  int         numIndices;
  const int   *indices;

  // This will be set to the index of the last (rightmost)
  // child to traverse
  int         lastChildIndex;

  // If this node is in a path, see which of our children are
  // in paths, and traverse up to and including the rightmost
  // of these nodes (the last one in the "indices" array).
  if (action->getPathCode(numIndices, indices) ==
      SoAction::IN_PATH) {
    lastChildIndex = indices[numIndices - 1];
  }

  // Otherwise, consider all of the children
  else {
    lastChildIndex = children->getLength() - 1;
  }

  // Now we are ready to traverse the children, skipping every
  // other one. For the SoGetBoundingBoxAction, however, we
  // have to do some extra work in between each pair of
  // children - we have to make sure the center points get
  // averaged correctly.
  if (action->isOfType(
        SoGetBoundingBoxAction::getClassTypeId())) {
    SoGetBoundingBoxAction *bba =
      (SoGetBoundingBoxAction *) action;
    SbVec3f  totalCenter(0.0, 0.0, 0.0);
    int      numCenters = 0;

    for (int i = 0; i <= lastChildIndex; i++) {
      children->traverse(bba, i);

      // If the traversal set a center point in the action,
      // add it to the total and reset for the next child.
      if (bba->isCenterSet()) {
        totalCenter += bba->getCenter();
        numCenters++;
        bba->resetCenter();
      }
    }
    // Now, set the center to be the average. Since the
    // centers were already transformed, there's no need to
    // transform the average.
    if (numCenters != 0) {
      bba->setCenter(totalCenter / (float)numCenters, FALSE);
    }
  }

  // For all other actions, just traverse every child
  else
    for (int i = 0; i <= lastChildIndex; i++) {
      children->traverse(action, i);
    }
}
Exemplo n.º 2
0
void
SoSwitch::doChild(SoAction *action, int matchIndex)
//
////////////////////////////////////////////////////////////////////////
{
    int32_t	which;

    if (whichChild.isIgnored())
	which = SO_SWITCH_NONE;

    else
	which = whichChild.getValue();

    // If index is inherited from state, get value from there
    if (which == SO_SWITCH_INHERIT) {

	which = SoSwitchElement::get(action->getState());

	// Make sure it is in range
	if (which >= getNumChildren())
	    which %= getNumChildren();
    }

    // Store resulting index in state if not already inherited from there
    else
	SoSwitchElement::set(action->getState(), which);

    // Now we have the real value to deal with

    switch (which) {

      case SO_SWITCH_NONE:
	break;

      case SO_SWITCH_ALL:
	// If traversing to compute bounding box, we have to do some
	// work in between children
	if (action->isOfType(SoGetBoundingBoxAction::getClassTypeId())) {
	    SoGetBoundingBoxAction *bba = (SoGetBoundingBoxAction *) action;
	    SbVec3f	totalCenter(0.0, 0.0, 0.0);
	    int		numCenters = 0;
	    int 	lastChild = (matchIndex >= 0 ? matchIndex :
				     getNumChildren()  - 1);

	    for (int i = 0; i <= lastChild; i++) {
		children->traverse(bba, i, i);
		if (bba->isCenterSet()) {
		    totalCenter += bba->getCenter();
		    numCenters++;
		    bba->resetCenter();
		}
	    }
	    // Now, set the center to be the average:
	    if (numCenters != 0)
		bba->setCenter(totalCenter / numCenters, FALSE);
	}
	else {
	    if (matchIndex >= 0)
		children->traverse(action, 0, matchIndex);
	    else
		children->traverse(action);
	}
	break;

      default:

	// Make sure index is reasonable
	if (which < 0 || which >= getNumChildren()) {
#ifdef DEBUG	
	    SoDebugError::post("SoSwitch::doChild",
			       "Child index %d is out of range %d - %d "
			       "(applying %s)",
			       which, 0, getNumChildren() - 1,
			       action->getTypeId().getName().getString());
#endif /* DEBUG */			       
	    break;
	}

	// Traverse indicated child
	if (matchIndex < 0 || matchIndex == which)
	    children->traverse(action, (int) which);
    }
}