/*! 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); } }
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); } }