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

    Iterating trough Field list?

    Cinema 4D SDK
    python r20 r21
    3
    6
    1.2k
    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.
    • S
      sandidolsak
      last edited by Manuel

      Hello,

      I wrote a script that does a simple check up if the selected object is used in any Link or InExcludeData field trough the scene (objects, tags, nodes..), so you can debug a messy project and find out which objects are important or not.

      I never updated it to include Field list, so I come here for help since I am lost.
      The code to crawl trough is as follows

      def iter_container(bc):
          for value in bc:
              if type(value[1]) == c4d.InExcludeData:
                  for i in range(0, value[1].GetObjectCount()):
                      if value[1].ObjectFromIndex(doc, i) == op:
                          return 1
              if value[1] == op:
                  return 1
      

      I figured out I have to check

      if type(value[1]) == c4d.FieldList:
      

      But how do iterate trough it and check each objects like with inexcludedata?

      Thanks for help!

      Sandi

      ferdinandF 1 Reply Last reply Reply Quote 0
      • ferdinandF
        ferdinand @sandidolsak
        last edited by ferdinand

        Hi,

        FieldLists are despite their name actually trees. To walk a FieldList you have to get the associated GeListHead and then traverse the graph of that head. But there are multiple special cases and scenarios of how the objects in this graph can be organized. You should read the docs on that. Below is a simple example on how to traverse the graph of a field list.

        Note that the returned objects of get_field_layers() are FieldLayers, not the BaseList2Ds you see in your object manager. You can get the associated objects with FieldLayer.GetLinkedObject(doc), but not all layers have an associated BaseList2D.

        Also: please don't type check with type() πŸ˜‰

        import c4d
        
        def get_field_layers(op):
            """ Returns all field layers that are referenced in a field list.
            """
            def flatten_tree(node):
                """ Listifies a GeListNode tree.
                """
                res = []
                while node:
                    res.append(node)
                    for child in node.GetChildren():
                        res += flatten_tree(child)
                    node = node.GetNext()
                return res
            
            # get the GeListHead for the FieldList
            root = op.GetLayersRoot()
            if root is None:
                return []
            # Get the first node under the GeListHead
            first = root.GetFirst()
            if first is None:
                return []
            
            # traverse the graph
            return flatten_tree(first)
        
        def main():
            """
            """
            fieldlists = [value for id, value in op.GetData() 
                          if isinstance(value, c4d.FieldList)]
            if not fieldlists:
                return
            
            for layer in get_field_layers(fieldlists[0]):
                print str(layer)[:79]
                print layer.GetLinkedObject(doc), "\n\n"
                
        if __name__=='__main__':
           main()
        

        Cheers
        zipit

        MAXON SDK Specialist
        developers.maxon.net

        1 Reply Last reply Reply Quote 1
        • ManuelM
          Manuel
          last edited by

          hello,

          First, for your next threads, please help us keeping things organised and clean. I know it's not your priority but it really simplify our work here.

          • Q&A New Functionality.
          • How to Post Questions especially the tagging part.

          As @zipit answer, i got nothing really to add here. Thanks for your answer.
          For more information you can have a look at our FieldList Manual and you will find information for python on this page c4d.FieldList

          Cheers,
          Manuel

          MAXON SDK Specialist

          MAXON Registered Developer

          1 Reply Last reply Reply Quote 0
          • S
            sandidolsak
            last edited by sandidolsak

            Hey zipit,

            thanks you so much for this, works like a charm.

            It only fails on Text and MoText object, I think it is because "font" attribute, it is returning error "AttributeError: Parameter value not accessible (object unknown in Python)"
            Any idea how to get around this?
            Edit: Found solution here: https://developers.maxon.net/forum/topic/10248/13738_iterate-attributes/5

            Manuel, thanks for pointing me to that, will follow it from now on np.

            p.s. sorry about type() I usually copy paste code until it works and that works πŸ˜‰

            Cheers,

            Sandi

            1 Reply Last reply Reply Quote 0
            • ferdinandF
              ferdinand
              last edited by ferdinand

              Hi,

              I am glad that it works for you. But I want to point out again that my function is only an example and might not work on all scenarios of field list setups. And on the type() thing, I just saw it quite often recently and it is well known Python pitfall. The problem is that type() does not take polymorphism into account (by design). It is meant to test if an objects is exactly a type. isinstance() and issubclass() are more appropriate choices for type checks.

              This is especially important in c4d due to its heavily object oriented nature and that you rarely deal with base types.

              Here is an example:

              import c4d
              from timeit import timeit
              
              def main():
                  """
                  """
                  op = c4d.BaseList2D(c4d.Ocube)
                  cmp_type = lambda : type(op) == c4d.BaseList2D
                  cmp_isin = lambda : isinstance(op, c4d.BaseList2D)
                  
                  print "op is of type BaseList2D:", cmp_type() # False: whoops!
                  print "op ininstance of BaseList2D:", cmp_isin() # True
                  
                  # And it also peforms almost the same
                  print "Average execution time of type: ", timeit(cmp_type), "usec"
                  print "Average execution time of isinstance: ", timeit(cmp_isin), "usec"
                  
              if __name__=='__main__':
                 main()
              
              op is of type BaseList2D: False
              op isinstance of BaseList2D: True
              Average execution time of type:  0.403712 usec
              Average execution time of isinstance:  0.5232223 usec
              

              Cheers
              zipit

              MAXON SDK Specialist
              developers.maxon.net

              S 1 Reply Last reply Reply Quote 0
              • ManuelM
                Manuel
                last edited by Manuel

                hello,

                I've forked the question to this thread

                cheers,
                Manuel

                MAXON SDK Specialist

                MAXON Registered Developer

                1 Reply Last reply Reply Quote 0
                • mikeudinM mikeudin referenced this topic on
                • First post
                  Last post