how to get all subobject(children) of active object?
-
Hi everyone~~
I want to get all subobject(children) of active object.This is my idea :
import c4d from c4d import gui # Welcome to the world of Python def all_child(obj): if not obj: return elif obj.GetDown(): return obj.GetDown() elif obj.GetNext(): return obj.GetNext() while obj.GetUp() and not obj.GetNext(): obj = obj.GetUp() return obj.GetNext() def main(): obj = doc.GetActiveObject() if not obj: return objs = [] if obj.GetDown(): while obj: objs.append(obj) obj = all_child(obj) else: objs.append(obj) print len(objs),objs # Execute main() if __name__=='__main__': main()
but something is wrong, i don't know how to fix it.
somebody can help me? -
Is anyone here?
-
Hi,
there are basically two approaches how you can do this: iteratively and recursively. The recursive approach is somewhat easier to implement / more readable, but has the disadvantage that you actually might hit Python's recursion limit when dealing with a graph with 100's of objects. It might look something like this:
import c4d def get_descendants(op): """ Returns all descendants of op. """ if not isinstance(op, c4d.GeListNode): return [] res = [] for child in op.GetChildren(): res.append(child) res += get_descendants(child) # recursion happens here return res # Main function def main(): for node in get_descendants(op): print node # Execute main() if __name__=='__main__': main()
The iterative approach is a bit more complex in implementation but does not have this disadvantage. If you need an iterative approach - as your code does go into that direction -, just ask.
Cheers
zipit -
@zipit
Thank you zipit.
I find your methods convenient, but I still need an iterative approach
Can you give me some simple example?Cheers
-
Hi,
I am not sure what you would consider a simple example. I have once written this here. It does a bit more than (then?, argh, the English language ;)) you are asking for, but should show the principle. Its actually not that hard, you only have to find "your" algorithm to navigate the graph. There is no one way to do it (you can do it for example depth first or breadth first). Building a simple example graph and doing it on paper by hand might help. That is also why it is not easy to debug your example for you.
def iter_node(node, include_node=False, include_siblings=False): """Provides a non-recursive iterator for all descendants of a node. Args: node (c4d.GeListNode): The node to iterate over. include_node (bool, optional): If node itself should be included in the generator. Defaults to False. include_siblings (bool, optional): If the siblings (and their descendants) of node should be included. Will implicitly include node (i.e. set include_node to True). Defaults to False. Yields: c4d.GeListNode: A descendant of node. Example: For the following graph with object.2 as the input node. object.0 object.1 object.2 object.3 object.4 object.5 object.6 object.7 object.8 >> for node in iter_node(object_2, False, False): >> print node.GetName() object.3 object.4 object.5 >> for node in iter_node(object_2, True, False): >> print node.GetName() object.2 object.3 object.4 object.5 >> for node in iter_node(object_2, True, True): >> print node.GetName() object.1 object.2 object.3 object.4 object.5 object.6 object.7 object.8 """ if not isinstance(node, c4d.GeListNode): msg = "The argument node has to be a c4d.GeListNode. Received: {}." raise TypeError(msg.format(type(node))) # Lookup lists input_node = node yielded_nodes = [] top_nodes = [] # Set top nodes (and set node to first sibling if siblings are included) if include_siblings: while node.GetNext(): node = node.GetNext() top_nodes = [node] while node.GetPred(): node = node.GetPred() top_nodes.append(node) else: top_nodes = [node] # Start of iterator while node: # Yield the current node if it has not been yielded yet if node not in yielded_nodes: yielded_nodes.append(node) if node is input_node and include_node: yield node elif node is not input_node: yield node # Get adjacent nodes is_top_node = node in top_nodes node_down = node.GetDown() node_next = node.GetNext() node_up = node.GetUp() if is_top_node: node_up = None if is_top_node and not include_siblings: node_next = None # Get the next node in the graph in a depth first fashion if node_down and node_down not in yielded_nodes: node = node_down elif node_next and node_next not in yielded_nodes: node = node_next elif node_up: node = node_up else: node = None
Cheers
zipit -
Hi @gheyret, thanks for reaching out us.
Although @zipit has already provide an exhaustive answer to the topic (thanks man!) , I warmly suggest to look also to
this blog post
[URL-REMOVED] from @fwilleke80 and also to have a look at Navigation in Lists and Trees section on the GeListNode Manual.Best, Riccardo
[URL-REMOVED] @maxon: This section contained a non-resolving link which has been removed.