Layers with the same name?



  • I store the layer of objects using the layer name in an external file.
    However, if layers do not have unique names, restoring the info (due to layers with the same name) will go wrong.

    Is there another way, besides layerdata, to get the correct layer?
    I do not want to use the layerdata, because then I have to store the layerdata link.

    So, basically, is there another way to distinguish layers, not using layerdata or the layer name?

    I hope I make myself clear.



  • Hi pim, thanks for reaching out us.

    With regard to your request I confirm that being GeMarker class not available in Python you are out of real chances to distinguish two layers sharing the same name.
    As written in the GeMarker Manual, a GeMarker object contains an unique ID used to identify BaseList2D based objects. Since a LayerObject inherits from BaseList2D in C++ you could use BaseList2D::GetMarker() to retrieve the corresponding unique GeMarker and use it to distinguish multiple layers.

    Best, Riccardo



  • Hi pim,

    I need to rectify my answer - kudos to @m_adam - since although you can't directly access GeMarker you can make use of the C4DAtom::FindUniqueID().

    At the same time, due to a known bug, it's likely that the FindUniqueID returned value might be properly represented in the Python Console.

    In R21 SP1 you can make use of hash(uniqueID) - see What's New in R21.1 - whilst in previous releases you might consider to use the sequence of ASCII value of the unique ID to generate a meaningful string.

        layers = doc.GetLayerObjectRoot()
        layer = layers.GetDown()
        
        while layer is not None:
            # get the unique ID
            uniqueID = layer.FindUniqueID(c4d.MAXON_CREATOR_ID)
    
            # create a string containing the uniqueID characters ASCII value
            asciiValuesUniqueID = ''
            for i in uniqueID:
                asciiValuesUniqueID += str(ord(i))
    
            # show results
            print 'name: ', layer.GetName(), '\n / asciiValuesUniqueID: ', asciiValuesUniqueID, '\n / hash(UniqueID): =', hash(uniqueID) 
            layer = layer.GetNext()
    

    Cheers, Riccardo



  • Thank you. I will try your solution.
    -Pim



  • I tried the solution and it "hangs" cinema.
    To me it seems that "uniqueID = layer.FindUniqueID(c4d.MAXON_CREATOR_ID)" returns strange values that cannot be interpreted correctly by hash(uniqueID);

    Here the output and the script.
    I used R21 to test.

     200
     217
     210
     152
     191
     170
     19
    12
    p 112
     237
    s 115
    R 82
     191
     23
     0
     0
    
    import c4d
    from c4d import gui
    
    def main():
        layers = doc.GetLayerObjectRoot()
        layer = layers.GetDown()
        
        while layer is not None:
            # get the unique ID
            uniqueID = layer.FindUniqueID(c4d.MAXON_CREATOR_ID)
    
            # create a string containing the uniqueID characters ASCII value
            asciiValuesUniqueID = ''
            for i in uniqueID:
                print i, ord(i)                    # added for debug
                asciiValuesUniqueID += str(ord(i))
    
            # show results
            # line below, is commented out. Otherwise cinema 4d 'Hangs''
            print 'name: ', layer.GetName(), '\n / asciiValuesUniqueID: ', asciiValuesUniqueID, '\n / hash(UniqueID): =', hash(uniqueID) 
            layer = layer.GetNext()
    
    # Execute main()
    if __name__=='__main__':
        main()
    '''


  • @pim said in Layers with the same name?:

    I tried the solution and it "hangs" cinema.
    I used R21 to test.

    @r_gigante said in Layers with the same name?:

    In R21 SP1 you can make use of hash(uniqueID) - see What's New in R21.1
    Especially Fixed a crash when hashing a c4d.storage.ByteSeq.

    FindUniqueID return a c4d.storage.ByteSeq so it's possible to dirrectly compare them.

    Like bellow:

    import c4d
    import random
    
    def CreateLayer(x):
        # Creates a new Layer in memory
        layer = c4d.documents.LayerObject()
        if layer is None:
            raise RuntimeError("Failed to create a Layer.")
    
        # Defines the Layer Name
        layer.SetName("My Super Layer")
        print "Created layer ID: {0}, color: {1}".format(x, layer[c4d.ID_LAYER_COLOR])
            
        return layer
    
    def GetUniqueID(layer):
        if not isinstance(layer, c4d.documents.LayerObject):
            raise TypeError("The passed layer object was not a LayerObject")
        
        return layer.FindUniqueID(c4d.MAXON_CREATOR_ID)
    
    def HierarchyIterator(obj):
        while obj:
            yield obj
            for opChild in HierarchyIterator(obj.GetDown()):
                yield opChild
            obj = obj.GetNext()
    
    # Main function
    def main():    
        # Creates 5 layers with the same name
        layer1 = CreateLayer(1)
        layer2 = CreateLayer(2)
        layer3 = CreateLayer(3)
        layer4 = CreateLayer(4)
        layer5 = CreateLayer(5)
        
        # Store their uuid
        layerIdList = []
        layerIdList.append(GetUniqueID(layer1))
        layerIdList.append(GetUniqueID(layer2))
        layerIdList.append(GetUniqueID(layer3))
        layerIdList.append(GetUniqueID(layer4))
        layerIdList.append(GetUniqueID(layer5))
        
        # Insert them randomly
        layerList = []
        layerList.append(layer1)
        layerList.append(layer2)
        layerList.append(layer3)
        layerList.append(layer4)
        layerList.append(layer5)
    
        # Shuffle the list and insert them in the doc
        rootLayers = doc.GetLayerObjectRoot()
        if rootLayers is None:
            raise RuntimeError("Failed to retrieve the Root Layer.")
        
        random.shuffle(layerList)
        for layer in layerList:
            # Inserts the layer into the LayerRoot, in the document
            layer.InsertUnder(rootLayers)
            
        
        print "--------"
        
        # Now iterates over each layer in the doc and print their their color.
        for layer in HierarchyIterator(rootLayers.GetDown()):
            layerUuid = GetUniqueID(layer)
            try:
                # Find the index that match our byteseq
                layerCreatedId = layerIdList.index(layerUuid) + 1
                print "Created layer ID: {0}, color: {1}".format(layerCreatedId, layer[c4d.ID_LAYER_COLOR])
                
            # If the uuid is not found maybe the layer was already present previously
            except ValueError:
                continue
        
        c4d.EventAdd()
        
    # Execute main()
    if __name__=='__main__':
        main()
    

    Cheers,
    Maxime.



  • Thank you, that explains a lot.
    One question, how to print a ByteSeq or store it as a integer or ascii value?



  • @pim said in Layers with the same name?:

    Thank you, that explains a lot.
    One question, how to print a ByteSeq or store it as a integer or ascii value?

    Riccardo already demonstrated you how to convert a ByteSeq in ascii value (of course since ByteSeq is a ByteSeq.... some Byte can't be converted to a string).

        opUuid = op.FindUniqueID(c4d.MAXON_CREATOR_ID)
    
        print str(opUuid).encode("hex") # Display in hex
    
        # display each int value for character
        for x in range(0, len(opUuid)):
            print ord(opUuid[x])
    ```
    
    Cheers,
    Maxime.


  • Thanks, it is clear to me now.
    I am using str(opUuid).encode("hex") now.



  • Since R21 sp1 issue regarding ByteSeq not being able to be printed in the Python Console is resolved.

    Cheers,
    Maxime.


Log in to reply