Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    Layer Selection Python

    Cinema 4D SDK
    python r21
    3
    11
    1.5k
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • ROMANR
      ROMAN
      last edited by ROMAN

      Hi for everyone! I have an easy code which show the hidden layer but i don't understand how change it for do the same for:

      1. selected layers
      2. all layers(not only for children).

      Code

      import c4d

      def main():

      doc.StartUndo()
      root = doc.GetLayerObjectRoot() 
      
      LayersList = root.GetChildren()
      for layer in LayersList:
         doc.AddUndo(c4d.UNDOTYPE_CHANGE,layer)
         layer [c4d.ID_LAYER_VIEW] = 1
      
      
      doc.EndUndo()
      c4d.EventAdd()
      

      if name=='main':
      main()

      ferdinandF 1 Reply Last reply Reply Quote 0
      • CairynC
        Cairyn
        last edited by

        Check for the active bit by GetBit(c4d.BIT_ACTIVE) to test whether a layer is selected.
        Layers are GeListNodes, so you can get from one layer object to the other with the usual functions GetNext(), GetDown() etc.

        1 Reply Last reply Reply Quote 0
        • CairynC
          Cairyn
          last edited by

          Also, you are not looking at "only the children". The object you get from GetLayerObjectRoot() is a GeListHead, not a LayerObject, so you need to go from root either to the first layer in the list by GetDown(), or you get the full layer list on the top level(!) by GetChildren().

          Each of these layers in the returned list can have children, though, since layers form a full tree structure. So if you want to visit all layers, you need to recurse into the child lists as well. E.g.:

          import c4d
          
          def visitLayer(layer):
              if layer == None: return
              print (layer.GetName(), "Selected" if layer.GetBit(c4d.BIT_ACTIVE) else "Unselected")
              visitLayer(layer.GetDown())
              visitLayer(layer.GetNext())
              
          def main():
              first = doc.GetLayerObjectRoot().GetDown()
              visitLayer(first)
          
          if __name__=='__main__':
              main()
          
          ROMANR 1 Reply Last reply Reply Quote 2
          • ferdinandF
            ferdinand @ROMAN
            last edited by ferdinand

            Hello @roman,

            thank you for reaching out to us. And thank you @Cairyn for providing an answer. A minor problem with the answer provided by @Cairyn is that it is recursive. We recommend walking node graphs iteratively and not recursively, because of the vastness of node graphs in Cinema 4D and danger of producing stack overflows when walking them recusively. In this case, the case of layers, it is unlikely that one will hit the recursion limit of Python (one thousand recursions by default on most systems¹) or produce a stack overflow in C++ (depends on many things).

            Cheers,
            Ferdinand

            ¹ The recursion limit of Python is defined and set in sys via sys.get/setrecursionlimit. One can raise the limit of one thousand which is rather conservative, but if it is set to high, it will then fail to prevent what it is intended for: to prevent stack overflows and crashing the Python interpereter.

            MAXON SDK Specialist
            developers.maxon.net

            1 Reply Last reply Reply Quote 1
            • CairynC
              Cairyn
              last edited by

              This post is deleted!
              1 Reply Last reply Reply Quote 0
              • ROMANR
                ROMAN @Cairyn
                last edited by

                @cairyn said in Layer Selection Python:

                Also, you are not looking at "only the children". The object you get from GetLayerObjectRoot() is a GeListHead, not a LayerObject, so you need to go from root either to the first layer in the list by GetDown(), or you get the full layer list on the top level(!) by GetChildren().

                Each of these layers in the returned list can have children, though, since layers form a full tree structure. So if you want to visit all layers, you need to recurse into the child lists as well. E.g.:

                import c4d
                
                def visitLayer(layer):
                    if layer == None: return
                    print (layer.GetName(), "Selected" if layer.GetBit(c4d.BIT_ACTIVE) else "Unselected")
                    visitLayer(layer.GetDown())
                    visitLayer(layer.GetNext())
                    
                def main():
                    first = doc.GetLayerObjectRoot().GetDown()
                    visitLayer(first)
                
                if __name__=='__main__':
                    main()
                

                Thank you a lot Cairyn!!!

                1 Reply Last reply Reply Quote 0
                • ROMANR
                  ROMAN
                  last edited by

                  @cairyn, i don't understand just one thing how should i change a code if i want to do it with selected objects not for all.

                  import c4d

                  def visitLayer(layer):
                  if layer == None: return
                  print (layer.GetName())
                  doc.AddUndo(c4d.UNDOTYPE_CHANGE, layer)
                  layer [c4d.ID_LAYER_VIEW] = 1
                  visitLayer(layer.GetDown())
                  visitLayer(layer.GetNext())

                  def main():
                  doc.StartUndo()
                  first = doc.GetLayerObjectRoot().GetDown()
                  visitLayer (first)

                  doc.EndUndo()
                  c4d.EventAdd()
                  

                  if name=='main':
                  main()

                  CairynC 1 Reply Last reply Reply Quote 0
                  • CairynC
                    Cairyn @ROMAN
                    last edited by

                    @roman If you mean handle only the selected layers then you just need to insert a check for the active bit:

                    print (layer.GetName())
                    if layer.GetBit(c4d.BIT_ACTIVE) :
                        doc.AddUndo(c4d.UNDOTYPE_CHANGE, layer)
                        layer [c4d.ID_LAYER_VIEW] = 1
                    

                    If you really mean selected objects, I'm not sure what you mean as your code doesn't refer to any objects?

                    ROMANR 1 Reply Last reply Reply Quote 0
                    • ROMANR
                      ROMAN @Cairyn
                      last edited by ROMAN

                      @cairyn
                      For example, we have 20 layers and i need to change visibility just for 2 layers in this list. That's what i meant when i talked about selected layers.

                      I tried to use same code but it showed to me first layer in list....while i want to work with active layers which i have selected.

                      And i wanted to ask which command delete layer?

                      Sorry for stupid questions, but SDK a little bit unobvious.

                      CairynC 1 Reply Last reply Reply Quote 0
                      • CairynC
                        Cairyn @ROMAN
                        last edited by

                        @roman Just insert the code from my last post into the overall script.

                        Here, I did it for you this time:

                        import c4d
                        
                        def visitLayer(layer):
                            while layer != None:
                                if layer.GetBit(c4d.BIT_ACTIVE) :
                                    doc.AddUndo(c4d.UNDOTYPE_CHANGE, layer)
                                    layer [c4d.ID_LAYER_VIEW] = not layer [c4d.ID_LAYER_VIEW]
                                visitLayer(layer.GetDown())
                                layer = layer.GetNext()
                            
                        def main():
                            doc.StartUndo()
                            first = doc.GetLayerObjectRoot().GetDown()
                            visitLayer(first)
                            doc.EndUndo()
                            c4d.EventAdd()
                        
                        if __name__=='__main__':
                            main()
                        

                        This script toggles the editor visibility of the currently selected layers. Execute it twice to get the original visibility state back.

                        Note:

                        1. Since Ferdinand didn't like the overall recursion, I replaced the next-recursion with a while loop. The depth recursion is still there but if you manage to break the Python stack with your nested layer setup, your amount of layers is sus.
                        2. Layers do not have a method to get a list of selected elements last time I looked, so you need to traverse the whole layer tree and check the BIT_ACTIVE for each.

                        (If you are not happy about the structure of Maxon's API documentation, I do have many beginner-oriented lessons and examples in my course https://www.patreon.com/cairyn -- although Patreon is admittedly not ideal for searching; I really need to make this into a proper book.)

                        As for deleting a layer, a LayerObject is a BaseList2D which is a GeListNode, so you can use the Remove method. Like here:

                        import c4d
                        
                        def visitLayer(layer):
                            while layer != None:
                                nextLayer = layer.GetNext()
                                if layer.GetBit(c4d.BIT_ACTIVE) :
                                    doc.AddUndo(c4d.UNDOTYPE_DELETE, layer)
                                    layer.Remove()
                                else:
                                    visitLayer(layer.GetDown())
                                layer = nextLayer
                            
                        def main():
                            doc.StartUndo()
                            first = doc.GetLayerObjectRoot().GetDown()
                            visitLayer(first)
                            doc.EndUndo()
                            c4d.EventAdd()
                        
                        if __name__=='__main__':
                            main()
                        

                        The infrastructure of C4D will remove the objects from that layer and throw the layer away once there are no more references.

                        Note: Since the layer tree is a linked structure, you will need to pay extra attention to the tree walking, be it recursion or iteration, when you remove layers out of the structure. That's why the visitLayer function looks a bit different here.

                        1 Reply Last reply Reply Quote 1
                        • ROMANR
                          ROMAN
                          last edited by

                          @cairyn Thank you again. I will check your patreon

                          1 Reply Last reply Reply Quote 0
                          • First post
                            Last post