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

Reply via email to