Solved 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.