Copying Layers along with Objects



  • Hello!

    I'm trying to copy an object from one document to another using GetClone(), which works for that. But if I have the object with a Layer that Layer is not copied over to the new document. Is there a way to automatically copy the Layer along with the object?

    User preformed copy/paste does bring over the Layer, but using this code it doesn't.

            // with two documents open and an object selected
            BaseDocument* activedocument = GetActiveDocument();
            BaseDocument* firstdoc = GetFirstDocument();
            
            BaseObject* first = activedocument->GetFirstObject();
            BaseObject* clone = static_cast<BaseObject*>(first->GetClone(COPYFLAGS::NONE, nullptr));
            firstdoc->InsertObject(clone, nullptr, nullptr);
            EventAdd();
    

    Dan



  • As I understand it, you need to copy the layers separately and then restore the connections by using an AliasTrans object.

    Here's some code in Python, is faster to prototype, sorry:

    import c4d
    from c4d import gui
    
    def main():
        if op == None: return
    
        activeDoc = c4d.documents.GetActiveDocument() # source
        firstDoc = c4d.documents.GetFirstDocument() # target
        # user must make sure that the first doc is really the target
        # and the second doc active!
    
        trans = c4d.AliasTrans()
        if not trans or not trans.Init(doc):
            return
    
        firstDoc.StartUndo()
    
        op2 = op.GetClone(c4d.COPYFLAGS_RECURSIONCHECK, trans)
        op2[c4d.ID_BASELIST_NAME] = "This is a clone!"
        firstDoc.InsertObject(op2)
    
        layer = op.GetLayerObject(activeDoc)
        layercopy = layer != None
        if layercopy:
            layer2 = layer.GetClone(c4d.COPYFLAGS_RECURSIONCHECK, trans)
            if layer2 == None: 
                print "Layer copy failed"
                layercopy = False
            else:
                layerHead = firstDoc.GetLayerObjectRoot() # should return GeListHead
                # but returns BaseList2D
                if layerHead == None:
                    print "Layer head not returned"
                    layercopy = False
                else:
                    layer2.InsertUnder(layerHead)
                    # layerHead.InsertFirst(layer2)
        else:
            print "No layer to copy"
    
        trans.Translate(True)
    
        firstDoc.AddUndo(c4d.UNDOTYPE_NEW, op2)
        if layercopy:
            firstDoc.AddUndo(c4d.UNDOTYPE_NEW, layer2)
        firstDoc.EndUndo()
        c4d.EventAdd()
    
    if __name__=='__main__':
        main()
    

    AliasTrans is used in all clone operations, and then after inserting the elements into the new document, called with Translate to resolve all links that got broken during the separate clonings.

    Haven't tested whether this works for nested layers; the code obviously only copies the layer of the selected object; you may need to traverse the hierarchy to find all used layers and clone them.



  • As I understand it, you need to copy the layers separately and then restore the connections by using an AliasTrans object.

    Here's some code in Python, is faster to prototype, sorry:

    import c4d
    from c4d import gui
    
    def main():
        if op == None: return
    
        activeDoc = c4d.documents.GetActiveDocument() # source
        firstDoc = c4d.documents.GetFirstDocument() # target
        # user must make sure that the first doc is really the target
        # and the second doc active!
    
        trans = c4d.AliasTrans()
        if not trans or not trans.Init(doc):
            return
    
        firstDoc.StartUndo()
    
        op2 = op.GetClone(c4d.COPYFLAGS_RECURSIONCHECK, trans)
        op2[c4d.ID_BASELIST_NAME] = "This is a clone!"
        firstDoc.InsertObject(op2)
    
        layer = op.GetLayerObject(activeDoc)
        layercopy = layer != None
        if layercopy:
            layer2 = layer.GetClone(c4d.COPYFLAGS_RECURSIONCHECK, trans)
            if layer2 == None: 
                print "Layer copy failed"
                layercopy = False
            else:
                layerHead = firstDoc.GetLayerObjectRoot() # should return GeListHead
                # but returns BaseList2D
                if layerHead == None:
                    print "Layer head not returned"
                    layercopy = False
                else:
                    layer2.InsertUnder(layerHead)
                    # layerHead.InsertFirst(layer2)
        else:
            print "No layer to copy"
    
        trans.Translate(True)
    
        firstDoc.AddUndo(c4d.UNDOTYPE_NEW, op2)
        if layercopy:
            firstDoc.AddUndo(c4d.UNDOTYPE_NEW, layer2)
        firstDoc.EndUndo()
        c4d.EventAdd()
    
    if __name__=='__main__':
        main()
    

    AliasTrans is used in all clone operations, and then after inserting the elements into the new document, called with Translate to resolve all links that got broken during the separate clonings.

    Haven't tested whether this works for nested layers; the code obviously only copies the layer of the selected object; you may need to traverse the hierarchy to find all used layers and clone them.



  • Hi Daniel, thanks for reaching out us.

    With regard to your question, @Cairyn's observations are indeed correct and there's nothing in our API automatically copying layer upon objects being copied.

    Cheers, R



  • Thanks, @Cairyn, that does work to copy the object and maintain the Layer link.

    The problem I'm running into with it, is that if you run your code multiple times each time the Layer gets copied over again. With a Cinema copy/paste it would link with the first Layer instead of inserting a new copy of the Layer.

    Would it be possible to duplicate that functionality?



  • @d_schmidt There are many more problems, this is just a snippet to demonstrate AliasTrans. E.g. If the copied object has children with other layers, these would not be copied. If the layer is child of another layer, then it would not be inserted in the right place. etc

    As for your question, I just checked: If you use the programmatic clone/insert/translate method and do NOT copy a layer in that AliasTrans, then the objects using that layer will NOT be relinked automatically with the "same" layer in the target scene, so the layer link remains empty. So I am afraid you will need to do everything manually:

    • check which layers are used in the copied hierarchy
    • determine which ones of these are already present in the target scene
    • for these, remember which objects are using them
    • also remember the structure of the layers (as they can be hierarchically ordered)
    • for layers that are not present in the target scene, copy them in the scope of the same AliasTrans
    • also copy layers that are needed as parents for copied layers but are not used themselves
    • then you insert everything in the target scene
    • finally, you use your own remembering structures to identify and restore all layer links that lead to layers that were already present in the target scene


  • @Cairyn Thanks again!

    That's what I was afraid of, but thanks for the information!


Log in to reply