//
// This is a patch for the Inventor 2.0 SoPath code. Three routines
// had bugs in them that affected some programs:
// The getLength() would return incorrect results sometimes for nodes
// with hidden children.
// The containsPath() method could return incorrect results if both
// paths contained hidden children
// And the isRelevantNotification method could cause core dumps when
// used with SoSF/MFPath fields.
//
//
// To apply this patch, compile this file into a .o and then link
// the .o before -lInventor. The linker may give a warning.
// This is normal and expected.
//
#include
#include
#include
#include
#include
////////////////////////////////////////////////////////////////////////
//
// Description:
// Returns the public length of the path.
//
// Use: public
int
SoPath::getLength() const
//
////////////////////////////////////////////////////////////////////////
{
// Cast const away...
SoPath *This = (SoPath *)this;
// If we aren't sure how many are public, figure it out:
if (numPublic == -1) {
int lastPublicIndex = 0;
if (minNumPublic > 1)
lastPublicIndex = minNumPublic - 1;
// Last test is for the second to last node.
// If it passes, then lastPublicIndex will be incremented to be the
// final node, which we don't need to test.
for ( ; lastPublicIndex < (getFullLength() - 1) ; lastPublicIndex++) {
// Children of this node will be private, so stop.
if ( ! nodes[lastPublicIndex]->isOfType(SoGroup::getClassTypeId()))
break;
}
This->numPublic = This->minNumPublic = lastPublicIndex + 1;
}
return numPublic;
}
////////////////////////////////////////////////////////////////////////
//
// Description:
// Returns TRUE if the nodes in the chain in the passed path are
// contained (in consecutive order) in this path chain.
//
// Use: public
SbBool
SoPath::containsPath(const SoPath *path) const
//
////////////////////////////////////////////////////////////////////////
{
int i, j;
// First find the head of the target path in this path
for (i = 0; i < getFullLength(); i++)
if (getNode(i) == path->getHead())
break;
// Head node is not there
if (i == getFullLength())
return FALSE;
// If there aren't enough nodes left in this path, then no match
if (getFullLength() - i < path->getFullLength())
return FALSE;
// Otherwise, start comparing nodes in the two paths to see if the
// paths match
for (j = 0; j < path->getFullLength(); j++)
if (path->getNode(j) != getNode(i + j))
return FALSE;
return TRUE;
}
////////////////////////////////////////////////////////////////////////
//
// Description:
// Returns TRUE if the given notification list involves a change to
// a node that affects the path. It is assumed that the last (most
// recent) node in the list is the head node of the path.
//
// Use: internal
SbBool
SoPath::isRelevantNotification(SoNotList *list) const
//
////////////////////////////////////////////////////////////////////////
{
// Trace down the notification list to find the first node (if
// any) that is not on the path. Stop when we reach the first
// (in time) record that was at a node in the graph.
const SoNotRec *rec = list->getLastRec();
const SoNotRec *prevRec = NULL;
int curIndex = 0;
SbBool offPath = FALSE;
while (rec != NULL && curIndex < getLength()) {
// Stop if the node in the current record is not the next node
// in the path
if (rec->getBase() != getNode(curIndex)) {
offPath = TRUE;
break;
}
// Go to the next record and path node, IF we're following a
// PARENT notification
if (rec->getPrevious() != NULL &&
rec->getPrevious()->getType() != SoNotRec::PARENT) {
break;
}
prevRec = rec;
rec = rec->getPrevious();
curIndex++;
}
// If not all notified nodes are on the path, we have to do some
// extra testing
if (offPath) {
const SoNode *node;
int index;
// The "rec" record points to a node that is off the path.
// Find out the index of this node in the parent node, which
// is pointed to by the previous record (which is guaranteed
// to exist and be on the path).
node = (const SoNode *) rec->getBase();
index= ((const SoNode *)prevRec->getBase())->getChildren()->find(node);
// If the node is to the right of the path, the change does
// not affect the path
if (index > getIndex(curIndex))
return FALSE;
// If it is to the left, it doesn't affect the path if any of
// the notification records go through a separator-type object:
else {
while (TRUE) {
if (! node->affectsState())
return FALSE;
rec = rec->getPrevious();
if (rec == NULL || rec->getType() != SoNotRec::PARENT)
break;
node = (const SoNode *) rec->getBase();
}
}
}
// If we made it this far, it's a relevant notification
return TRUE;
}
http://www.sgi.com/tech/Inventor/workarounds/PathPatch.2.0.C
(possibly inaccurate URL)
01/1995