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
    • Register
    • Login

    List All Nodes With No Filter?

    Cinema 4D SDK
    python 2023
    2
    3
    456
    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.
    • B
      bentraje
      last edited by

      Hi,

      I created a thread before on listing all nodes but it is limted to having a filter property.

      I tried using an empty dictionary but it errors.

      I just want to have a list of all the nodes in a given graph/material (like what doc.GetMaterials() does) and perform my own filtering later on.

      Is this possible?

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

        Hey @bentraje,

        Thank you for reaching out to us. Yes, GraphModelHelper.ListAllNodes requires at least one attribute to be set in the data dictionary. The method description also tries to conveys this, but erroneously uses the word 'can' where 'must' is meant:

        The passed DataDictionary can have one or multiple data defined.

        Meant is here:

        The passed DataDictionary must have at least one entry. When multiple entries are defined, only nodes matching all of them will be yielded.

        I will update that documentation. Regarding your question, I am afraid that the answer I gave in the old thread does not change much:

        [...] write your own little node traversal function.

        I understand that this can be a bit confusing, but in our APIs users are often expected to do data traversal themselves. In this case, call GraphNode.GetChildren recursively, plus some fluff of whatever one wants to do - printing trees, filtering nodes, etc. Find a code example below, but it is more or less the same as what I posted in the old thread.

        Cheers,
        Ferdinand

        Result for the default graph of the standard node space:
        aa00fc7c-06aa-4f17-bb96-63b96bd377a2-image.png

        This will already result in +400 lines because even for such seemingly simple graph, there are all the ports of the nodes which are not shown by default.

        Get all nodes:
        'Kind 1 node with the id '' at 0x000001A619A653D0
        'Kind 4 node with the id '>' at 0x000001A619A54B50
        'Kind 2 node with the id '<' at 0x000001A619A6D090
        'Kind 1 node with the id 'material' at 0x000001A619A6D150
        'Kind 4 node with the id '>' at 0x000001A619A66910
        'Kind 16 node with the id 'materialout' at 0x000001A619A78150
        'Kind 16 node with the id 'aovs' at 0x000001A619A69F10
        'Kind 16 node with the id 'spdlevel' at 0x000001A619A69D10
        'Kind 16 node with the id 'roundgeometry' at 0x000001A619A565D0
        'Kind 16 node with the id 'spd' at 0x000001A619A56590
        'Kind 16 node with the id 'displacementheight' at 0x000001A619A56790
        'Kind 16 node with the id 'displacement' at 0x000001A619A56810
        ...
        
        Get all in- and output ports:
        'Kind 16 node with the id 'materialout' at 0x000001A619A6D410
        'Kind 16 node with the id 'aovs' at 0x000001A619A765D0
        'Kind 16 node with the id 'spdlevel' at 0x000001A619A5E010
        'Kind 16 node with the id 'roundgeometry' at 0x000001A619A5D950
        ...
        

        Code:

        """Demonstrates how to traverse nodes in a node graph.
        
        Must be run from the Script Manager with a node material selected which has a node graph in the
        currently active node space, i.e., a material which produces an output for the currently active
        renderer.
        """
        
        import c4d
        import maxon
        import typing
        
        doc: c4d.documents.BaseDocument # The active document.
        
        def main():
            """Runs the example.
            """
            # Get the graph for the active material in the active node space.
            material: c4d.BaseMaterial = doc.GetActiveMaterial()
            if material is None:
                raise RuntimeError("No material selected.")
        
            nodeMaterial: c4d.NodeMaterial = material.GetNodeMaterialReference()
            if nodeMaterial is None:
                raise MemoryError(f"Could not access node material for {material}.")
        
            graph: maxon.GraphModelRef = nodeMaterial.GetGraph(c4d.GetActiveNodeSpaceId())
            if graph.IsNullValue():
                raise RuntimeError(f"There is no graph for {c4d.GetActiveNodeSpaceId()} in {material}")
                
            # Define our little traversal function.
            def GetDescendants(node: maxon.GraphNode, 
                               mask: tuple[maxon.NODE_KIND] = tuple()) -> typing.Iterator[maxon.GraphNode]:
                """Yields all descendants of #node including #node itself whose node kind matches #mask.
                """
                if len(mask) == 0 or node.GetKind() in mask:
                    yield node
                for child in node.GetChildren():
                    for descendant in GetDescendants(child, mask):
                        yield descendant
        
            # A function to pretty print nodes.
            PrintNode = lambda node: print (f"'Kind {node.GetKind()} node with the id '{node.GetId()}' at",
                                            f"0x{hex(id(node)).upper()[2:].zfill(16)}")
        
            # Use our function to traverse nodes ...
        
            # Iterate over all nodes below and including root.
            print("\nGet all nodes:")
            for node in GetDescendants(graph.GetRoot()):
                PrintNode(node) 
        
            # Iterate over all input and output ports below root.
            print("\nGet all in- and output ports:")
            for node in GetDescendants(graph.GetRoot(), (maxon.NODE_KIND.INPORT, maxon.NODE_KIND.OUTPORT)):
                PrintNode(node) 
        
        if __name__ == "__main__":
            main()
        

        MAXON SDK Specialist
        developers.maxon.net

        1 Reply Last reply Reply Quote 1
        • B
          bentraje
          last edited by

          RE: Yes, GraphModelHelper.ListAllNodes requires at least one attribute to be set in the data dictionary.

          Gotcha. Thanks for the clarification.
          Anyway, the suggested alternative (i.e. write a separate iterator) still works as expected. Same as before.

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