Hi Dirk,
Dirk Reiners wrote:
> Hi everybody,
>
> ok, ok, I got it. My head is starting to cave in from all the blows. ;)
>
> But to get a better idea of what everybody is thinking of, I pose the
> following challenge: Everybody who thinks he knows what the right level
> of documentation is (and that's nearly everybody in the discussion,
> right? ;) should document a file to the level that he or she thinks is
> right. Given that Node has come up as an important and underdocumented
> thing, please use that. I attached the current OSGNode.h and .cpp, and
> I'm looking forward to your versions while I prepare mine. ;)
ok, here is my version - for the record: it took about an hour and a
half to write, I'm not a native English speaker so most sentences went
through the a number of changes.
Cheers,
Carsten
/*---------------------------------------------------------------------------*\
* OpenSG *
* *
* *
* Copyright 2000-2006 by OpenSG Forum *
* *
* contact: [EMAIL PROTECTED], [EMAIL PROTECTED], [EMAIL PROTECTED] *
* *
\*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*\
* License *
* *
* This library is free software; you can redistribute it and/or modify it *
* under the terms of the GNU Library General Public License as published *
* by the Free Software Foundation, version 2. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
* *
\*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*\
* Changes *
* *
* *
* *
* *
* *
* *
\*---------------------------------------------------------------------------*/
#ifdef OSG_DOC_FILES_IN_MODULE
/*! \file OSGNode.cpp
\ingroup GrpSystemFieldContainer
*/
#endif
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <functional>
#include <algorithm>
#include "OSGConfig.h"
#include "OSGFieldContainerPtr.h"
#include "OSGFieldContainerType.h"
#include "OSGNode.h"
#include "OSGNodeCore.h"
#include "OSGBinaryDataHandler.h"
#include "OSGSFFieldContainerPtr.h"
#include "OSGMFFieldContainerPtr.h"
OSG_USING_NAMESPACE
const BitVector Node::VolumeFieldMask =
(TypeTraits<BitVector>::One << Node::VolumeFieldId );
const BitVector Node::TravMaskFieldMask =
(TypeTraits<BitVector>::One << Node::TravMaskFieldId );
const BitVector Node::ParentFieldMask =
(TypeTraits<BitVector>::One << Node::ParentFieldId );
const BitVector Node::ChildrenFieldMask =
(TypeTraits<BitVector>::One << Node::ChildrenFieldId );
const BitVector Node::CoreFieldMask =
(TypeTraits<BitVector>::One << Node::CoreFieldId );
FieldDescription *Node::_desc[] =
{
new FieldDescription(SFDynamicVolume::getClassType(),
"volume",
OSG_FC_FIELD_IDM_DESC(VolumeField),
false,
(FieldAccessMethod) &Node::getSFVolume),
// Yes, this is wrong, it should be an UInt32, but changing
// it now will break all old .osb files, and this info is
// nearly never necessary to be loaded from files.
new FieldDescription(SFBool::getClassType(),
"travMask",
OSG_FC_FIELD_IDM_DESC(TravMaskField),
false,
(FieldAccessMethod) &Node::getSFTravMask),
new FieldDescription(SFNodePtr::getClassType(),
"parent",
OSG_FC_FIELD_IDM_DESC(ParentField),
true,
(FieldAccessMethod) &Node::getSFParent),
new FieldDescription(MFNodePtr::getClassType(),
"children",
OSG_FC_FIELD_IDM_DESC(ChildrenField),
false,
(FieldAccessMethod) &Node::getMFChildren),
new FieldDescription(SFNodeCorePtr::getClassType(),
"core",
OSG_FC_FIELD_IDM_DESC(CoreField),
false,
(FieldAccessMethod) &Node::getSFCore)
};
FieldContainerType Node::_type(
"Node",
"AttachmentContainer",
0,
(PrototypeCreateF) &Node::createEmpty,
0,
_desc,
sizeof(_desc));
const NodePtr Node::NullNode(NullFC);
OSG_FIELD_CONTAINER_DEF(Node, NodePtr)
/*-------------------------------------------------------------------------*/
/* Set */
/**
* Set the core for this Node, replacing an existing one and adding this Node
* to the list of parents of the core.
* @param core The core to set, can be NullFC to clear the current one.
*/
void Node::setCore(const NodeCorePtr &core)
{
NodePtr thisP = getPtr();
thisP.setParentFieldPos(CoreFieldId);
addRefCP(core);
if(_sfCore.getValue() != NullFC)
{
beginEditCP(_sfCore.getValue(), NodeCore::ParentsFieldMask);
{
_sfCore.getValue()->subParent(thisP);
}
endEditCP (_sfCore.getValue(), NodeCore::ParentsFieldMask);
subRefCP(_sfCore.getValue());
}
_sfCore.setValue(core);
if(_sfCore.getValue() != NullFC)
{
beginEditCP(_sfCore.getValue(), NodeCore::ParentsFieldMask);
{
_sfCore.getValue()->addParent(thisP);
}
endEditCP (_sfCore.getValue(), NodeCore::ParentsFieldMask);
}
// TODO Check if required (GV)
invalidateVolume();
}
/*-------------------------------------------------------------------------*/
/* Children */
/**
* Add a child to this Node, become its parent and append it to the
* list of children. If childP is already the child of a different Node it is
* removed there and added to this Node.
* @param childP The child to add.
*/
void Node::addChild(const NodePtr &childP)
{
if(childP != NullFC)
{
// do the ref early, to prevent destroys on getParent(a)->addChild(a)
addRefCP(childP);
// already somebody else's child?
NodePtr parent = childP->getParent();
if(parent != NullFC)
{
beginEditCP(parent, Node::ChildrenFieldMask);
parent->subChild(childP);
endEditCP (parent, Node::ChildrenFieldMask);
}
_mfChildren.push_back(childP);
beginEditCP(childP, Node::ParentFieldMask);
{
childP->setParent(getPtr());
}
endEditCP (childP, Node::ParentFieldMask);
// TODO Check if required (GV)
#ifndef OSG_GV_BETA
invalidateVolume();
#endif
}
}
/**
* Insert childP into the list of children at index childIndex and become its
* parent. If childP is already the child of a different Node it is removed
* there and added to this Node.
* @param childIndex Insertion index, valid range: [0, number of children].
* @param childP The child to insert.
*/
void Node::insertChild(UInt32 childIndex, const NodePtr &childP)
{
MFNodePtr::iterator childIt = _mfChildren.begin();
if(childP != NullFC)
{
// do the ref early, to prevent destroys on getParent(a)->addChild(a)
addRefCP(childP);
// already somebody else's child?
NodePtr parent = childP->getParent();
if(parent != NullFC)
{
beginEditCP(parent, Node::ChildrenFieldMask);
parent->subChild(childP);
endEditCP (parent, Node::ChildrenFieldMask);
}
childIt += childIndex;
_mfChildren.insert(childIt, childP);
beginEditCP(childP, Node::ParentFieldMask);
{
childP->setParent(getPtr());
}
endEditCP (childP, Node::ParentFieldMask);
}
// TODO check if required (GV)
#ifndef OSG_GV_BETA
invalidateVolume();
#endif
}
/**
* Replace the child at childIndex with childP and become its parent. If childP
* is already the child of a different Node it is removed there and added to
* this Node. The replaced child has its parent set to NullFC.
* @param childIndex Index of the child to replace, valid range
* [0, number of children -1]
* @param childP The child to put at childIndex.
*/
void Node::replaceChild(UInt32 childIndex, const NodePtr &childP)
{
if(childP != NullFC && childIndex < _mfChildren.size())
{
// do the ref early, to prevent destroys on getParent(a)->addChild(a)
addRefCP(childP);
// already somebody else's child?
// moved it up could be a child of childIndex.
NodePtr parent = childP->getParent();
if(parent != NullFC)
{
beginEditCP(parent, Node::ChildrenFieldMask);
parent->subChild(childP);
endEditCP (parent, Node::ChildrenFieldMask);
}
// remove the current child
beginEditCP(_mfChildren[childIndex], Node::ParentFieldMask);
{
_mfChildren[childIndex]->setParent(NullNode);
}
endEditCP (_mfChildren[childIndex], Node::ParentFieldMask);
subRefCP(_mfChildren[childIndex]);
// set the new child
_mfChildren[childIndex] = childP;
beginEditCP(childP, Node::ParentFieldMask);
{
childP->setParent(getPtr());
}
endEditCP (childP, Node::ParentFieldMask);
}
// TODO check if required (GV)
#ifndef OSG_GV_BETA
invalidateVolume();
#endif
}
//! return true on success, false on child not found
/**
* Replace childP with newChildP, if childP is a child of this Node and become
* parent of newChildP. If newChildP is already the child of a different Node
* it is removed there and added to this Node. The replaced childP has its
* parent set to NullFC.
* @param childP Child to be replaced.
* @param newChildP Child to replace existing on with.
* @return True if replacement did happen, False if childP is not a child of
* this Node.
*/
bool Node::replaceChildBy(const NodePtr &childP,
const NodePtr &newChildP)
{
MFNodePtr::iterator childIt = _mfChildren.find(childP);
if(newChildP != NullFC)
{
if(childIt != _mfChildren.end())
{
// do the ref early, to prevent destroys on
// getParent(a)->addChild(a)
addRefCP(newChildP);
// already somebody else's child?
// moved it up could be a child of childP.
NodePtr parent = newChildP->getParent();
if(parent != NullFC)
{
beginEditCP(parent, Node::ChildrenFieldMask);
parent->subChild(newChildP);
endEditCP (parent, Node::ChildrenFieldMask);
}
beginEditCP(childP, Node::ParentFieldMask);
{
childP->setParent(NullNode);
}
endEditCP (childP, Node::ParentFieldMask);
subRefCP(childP);
(*childIt) = newChildP;
beginEditCP(newChildP, Node::ParentFieldMask);
{
newChildP->setParent(getPtr());
}
endEditCP (newChildP, Node::ParentFieldMask);
// TODO check if required (GV)
#ifndef OSG_GV_BETA
invalidateVolume();
#endif
return true;
}
}
return false;
}
/**
* Find the index of childP in the children list.
* @param childP Child to find.
* @return Index of childP or -1 if it is not found.
*/
Int32 Node::findChild(const NodePtr &childP) const
{
UInt32 index;
for(index = 0; index < _mfChildren.size(); index++)
{
if( _mfChildren[index] == childP)
break;
}
if(index < _mfChildren.size())
return index;
else
return -1;
}
/**
* Remove childP from the list of children of this Node, setting its parent to
* NullFC. Nothing happens if childP is not a child of this Node.
* @param childP Child to remove.
*/
void Node::subChild(const NodePtr &childP)
{
MFNodePtr::iterator childIt = _mfChildren.find(childP);
if(childIt != _mfChildren.end())
{
beginEditCP(childP, Node::ParentFieldMask);
{
childP->setParent(NullNode);
}
endEditCP (childP, Node::ParentFieldMask);
subRefCP(childP);
_mfChildren.erase(childIt);
}
else
{
SWARNING << "Node(" << this << ")::subChild: " << childP
<< " is not one of my children!" << std::endl;
}
// TODO check if required (GV)
#ifndef OSG_GV_BETA
invalidateVolume();
#endif
}
/**
* Remove the child at index childIndex in the list of children, setting its
* parent to NullFC.
* @param childIndex Index of child to remove,
* valid range: [0, number of children -1].
*/
void Node::subChild(UInt32 childIndex)
{
MFNodePtr::iterator childIt = _mfChildren.begin();
childIt += childIndex;
if(childIt != _mfChildren.end())
{
beginEditCP(*childIt, Node::ParentFieldMask);
{
(*childIt)->setParent(NullNode);
}
endEditCP (*childIt, Node::ParentFieldMask);
subRefCP(*childIt);
_mfChildren.erase(childIt);
}
// TODO check if required (GV)
#ifndef OSG_GV_BETA
invalidateVolume();
#endif
}
/*-------------------------------------------------------------------------*/
/* Get Transformation */
/**
* Return the transformation matrix that maps this Node's coordinate system to
* world coordinates.
* @return To world coordinates transformation matrix.
*/
Matrix Node::getToWorld(void)
{
Matrix tmp;
getToWorld(tmp);
return tmp;
}
/**
* Store the transformation matrix that maps this Node's coordinate system to
* world coordinates in result.
* @param result Matrix (link) to store the to world coordinates
* transformation in.
*/
void Node::getToWorld(Matrix &result)
{
if(getParent() != NullFC)
{
getParent()->getToWorld(result);
}
else
{
result.setIdentity();
}
if(getCore() != NullFC)
getCore()->accumulateMatrix(result);
}
/*-------------------------------------------------------------------------*/
/* Volume */
/**
* Store the bounding volume of this Node, which includes the subtree below it,
* in world coordinates in result.
* @param result DynamicVolume (link) to store the bounding volume in.
*/
void Node::getWorldVolume(DynamicVolume &result)
{
Matrix m;
if(getParent() != NullFC)
{
getParent()->getToWorld(m);
}
else
{
m.setIdentity();
}
updateVolume();
result = getVolume();
result.transform(m);
/*
Pnt3f low,high;
result.getBounds(low,high);
fprintf(stderr,"%p: node 0x%p gwv (%f %f %f %f %f %f)\n",
Thread::getCurrent(), this,
low[0], low[1], low[2],
high[0], high[1], high[2] );
*/
}
/**
* Recompute this Nodes bounding volume if it is invalid.
*/
void Node::updateVolume(void)
{
if(_sfVolume.getValue().getInstance().isValid() == true ||
getTravMask() == 0x0000)
{
return; // still valid, nothing to do
}
// be careful to not change the real volume. If two threads
// are updating the same aspect this will lead to chaos
DynamicVolume vol = _sfVolume.getValue();
//fprintf(stderr,"%p: node 0x%p update needed\n", Thread::getCurrent(), this);
MFNodePtr::iterator it;
vol.getInstance().setEmpty();
for(it = _mfChildren.begin(); it != _mfChildren.end(); ++it)
{
if((*it)->getTravMask())
{
(*it)->updateVolume();
vol.getInstance().extendBy((*it)->getVolume());
}
}
// test for null core. Shouldn't happen, but just in case...
if(getCore() != NullFC)
getCore()->adjustVolume(vol.getInstance());
NodePtr thisP = getPtr();
beginEditCP(thisP, VolumeFieldMask);
vol.instanceChanged();
_sfVolume.setValue(vol);
endEditCP(thisP, VolumeFieldMask);
}
/**
* Mark this Node's boundig volume as invalid.
*/
void Node::invalidateVolume(void)
{
Volume &vol=_sfVolume.getValue().getInstance();
if(vol.isValid() == true && vol.isStatic() == false)
{
NodePtr thisP = getPtr();
beginEditCP(thisP, VolumeFieldMask);
vol.setValid(false);
_sfVolume.getValue().instanceChanged();
endEditCP(thisP, VolumeFieldMask);
if(getParent() != NullFC)
{
getParent()->invalidateVolume();
}
}
}
/*-------------------------------------------------------------------------*/
/* Dump */
/**
* Create a debug dump of this Node.
* @param uiIndent Number of spaces to indent the output.
* @param bvFlags XXX unknown XXX
*/
void Node::dump( UInt32 uiIndent,
const BitVector bvFlags) const
{
UInt32 i;
NodePtr thisP = getPtr();
indentLog(uiIndent, PLOG);
PLOG << "Node"
<< "("
<< thisP.getFieldContainerId()
<< ") : "
<< _mfChildren.size()
<< " children | "
<< _attachmentMap.getValue().size()
<< " attachments | "
<< "Parent : " << std::hex;
if(_sfParent.getValue() != NullFC)
PLOG << "0x" << &(*(_sfParent.getValue())) << " | ";
else
PLOG << "NULL | ";
PLOG << "0x" << this << std::dec << std::endl;
indentLog(uiIndent, PLOG);
PLOG << "[" << std::endl;
if(_sfCore.getValue() != NullFC)
{
_sfCore.getValue()->dump(uiIndent + 4, bvFlags);
}
else
{
indentLog(uiIndent + 4, PLOG);
PLOG << "Core : " << "NULL" << std::endl;
}
Inherited::dump(uiIndent, bvFlags);
indentLog(uiIndent, PLOG);
PLOG << "]" << std::endl;
indentLog(uiIndent, PLOG);
PLOG << "{" << std::endl;
for(i = 0; i < _mfChildren.size(); i++)
{
_mfChildren[i]->dump(uiIndent + 4, bvFlags);
PLOG << std::endl;
}
indentLog(uiIndent, PLOG);
PLOG << "}" << std::endl;
/*
for(i = 0; i < indent; i++)
{
cerr << " ";
}
cerr << " Parent : ";
for(i = 0; i < indent; i++)
{
cerr << " ";
}
for(i = 0; i < indent; i++)
fprintf(stderr, " ");
fprintf(stderr, "NAttachments : \n");
map<UInt32, AttachmentPtr>::const_iterator fcI;
fcI = _attachmentMap.getValue().begin();
while(fcI != _attachmentMap.getValue().end())
{
(*fcI).second->dump(indent + 2);
++fcI;
}
for(i = 0; i < indent; i++)
{
cerr << " ";
}
cerr << "{" << std::endl;
for(i = 0; i < indent; i++)
{
cerr << " ";
}
cerr << "}" << std::endl;
*/
}
/*-------------------------------------------------------------------------*/
/* Constructors */
/**
* Default constructor.
*/
Node::Node(void) :
Inherited (),
_sfVolume (),
_sfTravMask (TypeTraits<UInt32>::getMax()),
_sfParent (),
_mfChildren (),
_sfCore ()
{
}
/**
* Copy constructor.
*/
Node::Node(const Node &source) :
Inherited (source),
_sfVolume (source._sfVolume),
_sfTravMask (source._sfTravMask),
_sfParent (),
_mfChildren (),
_sfCore ()
{
}
/*-------------------------------------------------------------------------*/
/* Destructor */
/**
* Destructor.
*/
Node::~Node(void)
{
if(_sfCore.getValue() != NullFC)
{
NodePtr thisP = getPtr();
beginEditCP(_sfCore.getValue(), NodeCore::ParentsFieldMask);
{
_sfCore.getValue()->subParent(thisP);
}
endEditCP (_sfCore.getValue(), NodeCore::ParentsFieldMask);
subRefCP(_sfCore.getValue());
}
MFNodePtr::iterator vChildIt = _mfChildren.begin();
MFNodePtr::const_iterator endChildren = _mfChildren.end ();
while(vChildIt != endChildren)
{
beginEditCP(*vChildIt, Node::ParentFieldMask);
{
(*vChildIt)->setParent(NullNode);
}
endEditCP (*vChildIt, Node::ParentFieldMask);
subRefCP(*vChildIt);
++vChildIt;
}
}
#if defined(OSG_FIXED_MFIELDSYNC)
void Node::onDestroyAspect(UInt32 uiId, UInt32 uiAspect)
{
_mfChildren.terminateShare(uiAspect, this->getContainerSize());
}
#endif
/**
* Create a shallow copy of the tree with root pRootNode. The copy will have
* its own Nodes (with the corrsponding parent/child relationships, except for
* the copy of the root, which has no parent), but share all NodeCores (link)
* with the original.
* @param pRootNode Root of the tree to copy.
* @return Root node of the copy.
*/
NodePtr OSG::cloneTree(const NodePtr &pRootNode)
{
NodePtr returnValue = NullFC;
if(pRootNode != NullFC)
{
NodePtr pChildClone = NullFC;
returnValue = Node::create();
beginEditCP(returnValue);
{
returnValue->setTravMask(pRootNode->getTravMask());
returnValue->setCore (pRootNode->getCore());
for(UInt32 i = 0; i < pRootNode->getNChildren(); i++)
{
pChildClone = cloneTree(pRootNode->getChild(i));
returnValue->addChild(pChildClone);
}
}
endEditCP (returnValue);
}
return returnValue;
}
// deep clone of a fieldcontainer.
// we should move this into OSGFieldContainer.cpp?
/**
* Create a deep copy of FieldContainer src, sharing only Fields of a type
* derived from one mentioned in share. The cloned FieldContainer will contain
* copies of all fields of the src, including copies of other FieldContainers
* referenced through pointers stored in fields, unless excluded through an
* entry in share.
* @param src FieldContainer to clone.
* @param share List of types to share between copies.
* @return A copy of the given FieldContainer.
*/
FieldContainerPtr OSG::deepClone(const FieldContainerPtr &src,
const std::vector<std::string> &share)
{
if(src == NullFC)
return NullFC;
const FieldContainerType &type = src->getType();
//FDEBUG(("deepClone: fieldcontainertype = %s\n", type.getCName()));
FieldContainerPtr dst = FieldContainerFactory::the()->createFieldContainer(type.getName().str());
//UInt32 fcount = type.getNumFieldDescs();
// ignore dynamic fields.
UInt32 fcount = osgMin(type.getNumFieldDescs(), dst->getType().getNumFieldDescs());
for(UInt32 i=1;i <= fcount;++i)
{
const FieldDescription* fdesc = type.getFieldDescription(i);
if(fdesc->isInternal())
continue;
BitVector mask = fdesc->getFieldMask();
Field *src_field = src->getField(i);
Field *dst_field = dst->getField(i);
const FieldType &ftype = src_field->getType();
std::string fieldType = ftype.getName().str();
// attachements
if(strcmp(fdesc->getCName(), "attachments") == 0)
{
SFAttachmentMap *amap = (SFAttachmentMap *) src_field;
AttachmentMap::const_iterator mapIt = amap->getValue().begin();
AttachmentMap::const_iterator mapEnd = amap->getValue().end();
beginEditCP(dst, mask);
for(; mapIt != mapEnd; ++mapIt)
{
FieldContainerPtr fc = mapIt->second;
bool shareit = false;
for(UInt32 k=0;k<share.size();++k)
{
FieldContainerType *fct = FieldContainerFactory::the()
->findType(share[k].c_str());
if(fc != NullFC && fct != NULL &&
fc->getType().isDerivedFrom(*fct))
{
shareit = true;
break;
}
}
if(!shareit)
fc = OSG::deepClone(fc, share);
if(fc != NullFC)
AttachmentContainerPtr::dcast(dst)->addAttachment(AttachmentPtr::dcast(fc));
}
endEditCP(dst, mask);
continue;
}
// field
if(strstr(ftype.getCName(), "Ptr") == NULL)
{
//FDEBUG(("deepClone: fieldname = %s fieldType = %s\n", fdesc->getCName(), fieldType.c_str()));
beginEditCP(dst, mask);
dst_field->setAbstrValue(*src_field);
endEditCP(dst, mask);
}
else // field with pointer
{
if(src_field->getCardinality() == FieldType::SINGLE_FIELD)
{
FieldContainerPtr fc = ((SFFieldContainerPtr *) src_field)->getValue();
bool shareit = false;
for(UInt32 k=0;k<share.size();++k)
{
FieldContainerType *fct = FieldContainerFactory::the()
->findType(share[k].c_str());
if(fc != NullFC && fct != NULL &&
fc->getType().isDerivedFrom(*fct))
{
shareit = true;
break;
}
}
if(!shareit)
fc = OSG::deepClone(fc, share);
if(fc != NullFC)
{
// increment reference counter!
addRefCP(fc);
beginEditCP(dst);
((SFFieldContainerPtr *) dst_field)->setValue(fc);
endEditCP(dst);
}
}
else if(src_field->getCardinality() == FieldType::MULTI_FIELD)
{
beginEditCP(dst, mask);
for(UInt32 j=0;j < ((MFFieldContainerPtr*)src_field)->size();++j)
{
FieldContainerPtr fc = (*(((MFFieldContainerPtr *)src_field)))[j];
bool shareit = false;
for(UInt32 k=0;k<share.size();++k)
{
FieldContainerType *fct = FieldContainerFactory::the()
->findType(share[k].c_str());
if(fc != NullFC && fct != NULL &&
fc->getType().isDerivedFrom(*fct))
{
shareit = true;
break;
}
}
if(!shareit)
fc = OSG::deepClone(fc, share);
if(fc != NullFC)
{
// increment reference counter!
addRefCP(fc);
((MFFieldContainerPtr *) dst_field)->push_back(fc);
}
}
endEditCP(dst, mask);
}
}
}
return dst;
}
/**
* Behaves like
* deepClone(const FieldContainerPtr &, const std::vector<std::string>&) (link),
* but instead of giving a list of type names to share, the respective group ids
* can be given.
* @param src FieldContainer to clone.
* @param shareGroupIds List of type group ids to share.
* @return A copy of the given FieldContainer.
*/
FieldContainerPtr OSG::deepClone(const FieldContainerPtr &src,
const std::vector<UInt16> &shareGroupIds)
{
std::vector<std::string> share;
share.reserve(shareGroupIds.size());
for(UInt32 i=0;i<shareGroupIds.size();++i)
{
const char *name = FieldContainerFactory::the()->findGroupName(shareGroupIds[i]);
if(name != NULL)
share.push_back(name);
}
return OSG::deepClone(src, share);
}
// shareString is a comma separated FieldContainer type list
// e.g. "Material, Geometry"
/**
* Behaves like
* deepClone(const FieldContainerPtr &, const std::vector<std::string>&) (link),
* but accepts a comma separated list of type names to share.
* @param src FieldContainer to clone.
* @param shareString Comma separated type names to share.
* @return A copy of the given FieldContainer.
*/
FieldContainerPtr OSG::deepClone(const FieldContainerPtr &src,
const std::string &shareString)
{
std::vector<std::string> share;
// parse comma separated names.
std::string::const_iterator nextComma;
std::string::const_iterator curPos = shareString.begin();
while(curPos < shareString.end())
{
nextComma = std::find(curPos, shareString.end(), ',');
// strip leading spaces
curPos = std::find_if(curPos, nextComma, std::not1(std::ptr_fun(isspace)));
share.push_back(std::string(curPos, nextComma));
if(nextComma != shareString.end())
curPos = ++nextComma;
else
break;
}
return OSG::deepClone(src, share);
}
// deep clone of attachements.
/**
* Create a deep copy of the attachments of node src and add them to dst, unless
* the attachment has a type derived from one mentioned in share, then it is
* shared between the nodes.
* @param src Node whose attachments are cloned.
* @param dst Node to which the cloned attachments are added.
* @param share List of types that are not copied, but shared.
*/
void OSG::deepCloneAttachments(const NodePtr &src, NodePtr &dst,
const std::vector<std::string> &share)
{
SFAttachmentMap *amap = (SFAttachmentMap *) src->getSFAttachments();
AttachmentMap::const_iterator mapIt = amap->getValue().begin();
AttachmentMap::const_iterator mapEnd = amap->getValue().end();
beginEditCP(dst, Node::AttachmentsFieldMask);
for(; mapIt != mapEnd; ++mapIt)
{
FieldContainerPtr fc = mapIt->second;
bool shareit = false;
for(UInt32 k=0;k<share.size();++k)
{
FieldContainerType *fct = FieldContainerFactory::the()
->findType(share[k].c_str());
if(fc != NullFC && fct != NULL &&
fc->getType().isDerivedFrom(*fct))
{
shareit = true;
break;
}
}
if(!shareit)
fc = OSG::deepClone(fc, share);
if(fc != NullFC)
dst->addAttachment(AttachmentPtr::dcast(fc));
}
endEditCP(dst, Node::AttachmentsFieldMask);
}
/**
* Behaves like
* deepCloneAttachments(const NodePtr &, NodePtr &, const std::vector<std::string>&) (link),
* but instead of giving a list of type names to share, the respective group ids
* can be given.
* @param src Node whose attachments are cloned.
* @param dst Node to which the cloned attachments are added.
* @param shareGroupIds List of type group ids that are not copied, but shared.
*/
void OSG::deepCloneAttachments(const NodePtr &src, NodePtr &dst,
const std::vector<UInt16> &shareGroupIds)
{
std::vector<std::string> share;
share.reserve(shareGroupIds.size());
for(UInt32 i=0;i<shareGroupIds.size();++i)
{
const char *name = FieldContainerFactory::the()
->findGroupName(shareGroupIds[i]);
if(name != NULL)
share.push_back(name);
}
OSG::deepCloneAttachments(src, dst, share);
}
// shareString is a comma separated FieldContainer type list
// e.g. "Material, Geometry"
/**
* Behaves like
* deepCloneAttachments(const NodePtr &, NodePtr &, const std::vector<std::string>&) (link),
* but accepts a comma separated list of type names to share.
* @param src Node whose attachments are cloned.
* @param dst Node to which the cloned attachments are added.
* @param shareString Comma separated type names to share.
*/
void OSG::deepCloneAttachments(const NodePtr &src, NodePtr &dst,
const std::string &shareString)
{
std::vector<std::string> share;
// parse comma separated names.
std::string::const_iterator nextComma;
std::string::const_iterator curPos = shareString.begin();
while(curPos < shareString.end())
{
nextComma = std::find(curPos, shareString.end(), ',');
// strip leading spaces
curPos = std::find_if(curPos, nextComma, std::not1(std::ptr_fun(isspace)));
share.push_back(std::string(curPos, nextComma));
if(nextComma != shareString.end())
curPos = ++nextComma;
else
break;
}
OSG::deepCloneAttachments(src, dst, share);
}
// deep clone of nodes.
NodePtr OSG::deepCloneTree(const NodePtr &src,
const std::vector<std::string> &share)
{
NodePtr dst = NullFC;
if(src != NullFC)
{
dst = Node::create();
deepCloneAttachments(src, dst, share);
beginEditCP(dst);
{
dst->setActive(src->getActive());
dst->setTravMask(src->getTravMask());
dst->setCore(NodeCorePtr::dcast(OSG::deepClone(src->getCore(), share)));
for(UInt32 i = 0; i < src->getNChildren(); i++)
dst->addChild(deepCloneTree(src->getChild(i), share));
}
endEditCP (dst);
}
return dst;
}
NodePtr OSG::deepCloneTree(const NodePtr &src,
const std::vector<UInt16> &shareGroupIds)
{
std::vector<std::string> share;
share.reserve(shareGroupIds.size());
for(UInt32 i=0;i<shareGroupIds.size();++i)
{
const char *name = FieldContainerFactory::the()->findGroupName(shareGroupIds[i]);
if(name != NULL)
share.push_back(name);
}
return OSG::deepCloneTree(src, share);
}
// shareString is a comma separated FieldContainer type list
// e.g. "Material, Geometry"
NodePtr OSG::deepCloneTree(const NodePtr &src,
const std::string &shareString)
{
std::vector<std::string> share;
// parse comma separated names.
std::string::const_iterator nextComma;
std::string::const_iterator curPos = shareString.begin();
while(curPos < shareString.end())
{
nextComma = std::find(curPos, shareString.end(), ',');
// strip leading spaces
curPos = std::find_if(curPos, nextComma, std::not1(std::ptr_fun(isspace)));
share.push_back(std::string(curPos, nextComma));
if(nextComma != shareString.end())
curPos = ++nextComma;
else
break;
}
return OSG::deepCloneTree(src, share);
}
/*-------------------------------------------------------------------------*/
/* cvs id's */
#ifdef __sgi
#pragma set woff 1174
#endif
#ifdef OSG_LINUX_ICC
#pragma warning( disable : 177 )
#endif
namespace
{
static Char8 cvsid_cpp[] = "@(#)$Id: $";
static Char8 cvsid_hpp[] = OSGNODE_HEADER_CVSID;
static Char8 cvsid_inl[] = OSGNODE_INLINE_CVSID;
}
/*---------------------------------------------------------------------------*\
* OpenSG *
* *
* *
* Copyright 2000-2006 by OpenSG Forum *
* *
* contact: [EMAIL PROTECTED], [EMAIL PROTECTED], [EMAIL PROTECTED] *
* *
\*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*\
* License *
* *
* This library is free software; you can redistribute it and/or modify it *
* under the terms of the GNU Library General Public License as published *
* by the Free Software Foundation, version 2. *
* *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; if not, write to the Free Software *
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
* *
\*---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------*\
* Changes *
* *
* *
* *
* *
* *
* *
\*---------------------------------------------------------------------------*/
#ifndef _OSGNODEIMPL_H_
#define _OSGNODEIMPL_H_
#ifdef __sgi
#pragma once
#endif
#ifdef OSG_DOC_FILES_IN_MODULE
/*! \file OSGNodeImpl.h
\ingroup GrpSystemFieldContainer
*/
#endif
#include <string>
#include <vector>
#include <OSGSystemDef.h>
#include <OSGBaseTypes.h>
#include <OSGMatrix.h>
#include <OSGFieldContainer.h>
#include <OSGSFSysTypes.h>
#include <OSGSFBaseTypes.h>
#include <OSGAttachmentContainer.h>
#include <OSGSFNodeCorePtr.h>
#include <OSGSFNodePtrImpl.h>
#include <OSGSFNodePtrDepImpl.h>
#include <OSGMFNodePtrImpl.h>
#include <OSGMFNodePtrDepImpl.h>
OSG_BEGIN_NAMESPACE
class NodeCore;
class BinaryDataHandler;
class FieldDescription;
/*! \ingroup GrpSystemFieldContainer
*/
class OSG_SYSTEMLIB_DLLMAPPING Node : public AttachmentContainer
{
/*========================= PROTECTED ===============================*/
protected:
/// The direct base class of this type.
typedef AttachmentContainer Inherited;
/*========================== PUBLIC =================================*/
public:
/// Numerical Ids for the fields of a Node.
enum
{
VolumeFieldId = Inherited::NextFieldId,
TravMaskFieldId = VolumeFieldId + 1,
ParentFieldId = TravMaskFieldId + 1,
ChildrenFieldId = ParentFieldId + 1,
CoreFieldId = ChildrenFieldId + 1,
NextFieldId = CoreFieldId + 1
};
static const BitVector VolumeFieldMask;
static const BitVector TravMaskFieldMask;
static const BitVector ParentFieldMask;
static const BitVector ChildrenFieldMask;
static const BitVector CoreFieldMask;
/// The type of a pointer to a Node.
typedef NodePtr Ptr;
/*---------------------------------------------------------------------*/
/*! \name General Fieldcontainer Declaration */
/*! \{ */
OSG_FIELD_CONTAINER_DECL(NodePtr)
/*! \} */
/*---------------------------------------------------------------------*/
/*! \name Core */
/*! \{ */
NodeCorePtr getCore( void );
NodeCorePtr getCore( void ) const;
void setCore(const NodeCorePtr &core);
/*! \} */
/*---------------------------------------------------------------------*/
/*! \name Parent */
/*! \{ */
NodePtr getParent(void);
/*! \} */
/*---------------------------------------------------------------------*/
/*! \name Children */
/*! \{ */
UInt32 getNChildren (void ) const;
void addChild (const NodePtr &childP );
void insertChild ( UInt32 childIndex,
const NodePtr &childP );
void replaceChild ( UInt32 childIndex,
const NodePtr &childP );
bool replaceChildBy(const NodePtr &childP,
const NodePtr &newChildP );
Int32 findChild (const NodePtr &childP ) const;
void subChild (const NodePtr &childP );
void subChild ( UInt32 childIndex);
NodePtr getChild ( UInt32 childIndex);
/*! \} */
/*---------------------------------------------------------------------*/
/*! \name Active / TravMask */
/*! \{ */
bool getActive (void ) const;
void setActive (bool val);
void setTravMask(UInt32 val);
UInt32 getTravMask(void ) const;
/*! \} */
/*---------------------------------------------------------------------*/
/*! \name Children */
/*! \{ */
NodePtr clone(void);
/*! \} */
/*---------------------------------------------------------------------*/
/*! \name Access Fields */
/*! \{ */
SFDynamicVolume *getSFVolume (void);
SFUInt32 *getSFTravMask(void);
SFNodePtr *getSFParent (void);
SFNodeCorePtr *getSFCore (void);
MFNodePtr *getMFChildren(void);
/*! \} */
/*---------------------------------------------------------------------*/
/*! \name Transformation */
/*! \{ */
Matrix getToWorld(void );
void getToWorld(Matrix &result);
/*! \} */
/*---------------------------------------------------------------------*/
/*! \name Volume */
/*! \{ */
DynamicVolume &getVolume (bool update );
const DynamicVolume &getVolume (void ) const;
void getWorldVolume (DynamicVolume &result);
void updateVolume (void );
void invalidateVolume(void );
/*! \} */
/*---------------------------------------------------------------------*/
/*! \name Changed */
/*! \{ */
virtual void changed(BitVector whichField,
UInt32 origin );
/*! \} */
/*---------------------------------------------------------------------*/
/*! \name Binary Access */
/*! \{ */
virtual UInt32 getBinSize (const BitVector &whichField);
virtual void copyToBin ( BinaryDataHandler &pMem,
const BitVector &whichField);
virtual void copyFromBin( BinaryDataHandler &pMem,
const BitVector &whichField);
/*! \} */
/*---------------------------------------------------------------------*/
/*! \name Dump */
/*! \{ */
virtual void dump( UInt32 uiIndent = 0,
const BitVector bvFlags = 0) const;
/*! \} */
/*========================= PROTECTED ===============================*/
protected:
friend class FieldContainer;
friend class FieldContainerType;
/*---------------------------------------------------------------------*/
/*! \name Type information */
/*! \{ */
/// Array of desciptors for a Node's fields.
static FieldDescription *_desc[];
/// Type object to identify this class.
static FieldContainerType _type;
static const NodePtr NullNode;
/*! \} */
/*---------------------------------------------------------------------*/
/*! \name Fields */
/*! \{ */
/// Bounding volume of this Node, contains the complete subtree below it.
SFDynamicVolume _sfVolume;
/**
* Traversal mask. Actions (link) only visit the Node and its children, when
* the bitwise and (&) of the traversal masks of action and node
* are nonzero.
*/
SFUInt32 _sfTravMask;
/// Parent of this Node.
SFNodePtr _sfParent;
/// Children of this Node.
MFNodePtr _mfChildren;
/// NodeCore (link) of this Node.
SFNodeCorePtr _sfCore;
/*! \} */
/*---------------------------------------------------------------------*/
/*! \name Constructors */
/*! \{ */
Node(void);
Node(const Node &source);
/*! \} */
/*---------------------------------------------------------------------*/
/*! \name Destructor */
/*! \{ */
virtual ~Node (void);
/*! \} */
/*---------------------------------------------------------------------*/
/*! \name MT Construction */
/*! \{ */
void setParent(const NodePtr &parent);
void onCreate (const Node *source = NULL);
#if defined(OSG_FIXED_MFIELDSYNC)
virtual void onDestroyAspect(UInt32 uiId, UInt32 uiAspect);
#endif
/*! \} */
/*---------------------------------------------------------------------*/
/*! \name Sync */
/*! \{ */
#if !defined(OSG_FIXED_MFIELDSYNC)
virtual void executeSync ( FieldContainer &other,
const BitVector &whichField);
void executeSyncImpl( Node *pOther,
const BitVector &whichField);
#else
virtual void executeSync ( FieldContainer &other,
const BitVector &whichField,
const SyncInfo &sInfo );
void executeSyncImpl ( Node *pOther,
const BitVector &whichField,
const SyncInfo &sInfo );
virtual void execBeginEdit (const BitVector &whichField,
UInt32 uiAspect,
UInt32 uiContainerSize);
void execBeginEditImpl (const BitVector &whichField,
UInt32 uiAspect,
UInt32 uiContainerSize);
#endif
/*! \} */
/*---------------------------------------------------------------------*/
/*! \name Pointer */
/*! \{ */
NodePtr getPtr(void) const;
/*! \} */
/*========================== PRIVATE ================================*/
private:
/* prohibit default function (move to 'public' if needed) */
void operator =(const Node &source);
};
/*! \ingroup GrpSystemFieldContainerFuncs
*/
OSG_SYSTEMLIB_DLLMAPPING
NodePtr cloneTree(const NodePtr &pRootNode);
OSG_SYSTEMLIB_DLLMAPPING
FieldContainerPtr deepClone(const FieldContainerPtr &src,
const std::vector<std::string> &share);
OSG_SYSTEMLIB_DLLMAPPING
FieldContainerPtr deepClone(const FieldContainerPtr &src,
const std::vector<UInt16> &shareGroupIds);
OSG_SYSTEMLIB_DLLMAPPING
FieldContainerPtr deepClone(const FieldContainerPtr &src,
const std::string &shareString = "");
OSG_SYSTEMLIB_DLLMAPPING
void deepCloneAttachments(const NodePtr &src, NodePtr &dst,
const std::vector<std::string> &share);
OSG_SYSTEMLIB_DLLMAPPING
void deepCloneAttachments(const NodePtr &src, NodePtr &dst,
const std::vector<UInt16> &shareGroupIds);
OSG_SYSTEMLIB_DLLMAPPING
void deepCloneAttachments(const NodePtr &src, NodePtr &dst,
const std::string &shareString = "");
OSG_SYSTEMLIB_DLLMAPPING
NodePtr deepCloneTree(const NodePtr &src,
const std::vector<std::string> &share);
OSG_SYSTEMLIB_DLLMAPPING
NodePtr deepCloneTree(const NodePtr &src,
const std::vector<UInt16> &shareGroupIds);
OSG_SYSTEMLIB_DLLMAPPING
NodePtr deepCloneTree(const NodePtr &src,
const std::string &shareString = "");
OSG_END_NAMESPACE
#define OSGNODE_HEADER_CVSID "@(#)$Id: $"
#endif /* _OSGNODEIMPL_H_ */
-------------------------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
_______________________________________________
Opensg-users mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/opensg-users