Loop Nodes #4
No reviewers
Labels
No Label
No Milestone
No project
No Assignees
2 Participants
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: dr.sybren/rignodes#4
Loading…
Reference in New Issue
Block a user
No description provided.
Delete Branch "cgtinker/powership:loop"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What's supported:
Untested / out of scope:
Concept:
Once a loop is found, it gets executed in one (recursive) call (if it contains nested loops).
...At first I attempted to make loops separated from the main loop event. While independent loops are easy to handle when standing alone, they lead to a lot of edge cases especially when nested.
For debugging purposes currently the "iteration" attribute of the nodes is visible in developer mode and can be reseted with the "Prepare Nodes" button. Also the example is mainly for debugging.
Future PR: "Group Inputs/Outputs" for loops so it's possible to have by example have "3x vectors" as "one" input and "2x rotations" as "one" output.
WIP: Loop Nodesto Loop NodesThansk for the PR, it's super interesting. I couldn't do a full review yet, but this at least covers some superficial things I noticed while reading through the code.
To me the required changes you had to do to implement this shows that the current code should be refactored. I think the
RigNodesNodeTree
andAbstractRigNodesNode
are getting too big and too coupled when it comes to the execution flow. Probably best to extract that to a class that's responsible for the overall tree execution. That would be for a different PR though. Just wanted to mention this as it's been on the back of my mind for a while now.@ -72,0 +76,4 @@
output_nodes = list()
for node in self.nodes:
if isinstance(node, LoopOutputNode):
output_nodes.append(node)
This can be written as:
And since it's only being iterated over once, there even no need to construct a list, so a generator expression does the trick as well:
@ -72,0 +82,4 @@
for output_node in output_nodes:
input_node = output_node._get_connection_node()
nodes = list(output_node._get_loop_nodes(input_node))
for node in nodes:
There is no need to construct a list here, just loop over the generator returned by
output_node._get_loop_nodes()
@ -72,0 +96,4 @@
) -> deque["AbstractRigNodesNode"]:
"""Runs (nested) loops.
:return: Node(s) to visit next."""
Formatting: when writing multi-line docstrings, the closing
"""
should be on a line of its own (see PEP 257)Sorry, still stumbling.
@ -200,2 +293,4 @@
return sock
@property
def _inputs(self):
What's the reason to have these properties? They don't seem to add anything.
Those properties are for the loop nodes. The idea has been to just "ignore the first socket" of the loop nodes by default so I can easily figure out what's the connected loop node have an easier time searching for nodes within loop. To do so, the loop nodes return:
self.inputs[1:]
The bpy.types.Node type seems to overwrite properties it introduces. I'd have preferred to do something like:
I also considered to overwriting the generators...
ED: I can remove the properties and just overwrite the
exec_order_prerequisites
for theLoopInputNode
, that's probably cleaner.I don't think it's a good idea to have this different behaviour with just an underscore difference in the name. This should be handled with something that's more clearly an overridable getter of sorts.
@ -202,0 +306,4 @@
"""Generator, yields nodes that should be executed before the loop output node."""
nodes = list(self._connected_nodes(self._inputs, "from_socket"))
if not input_node in nodes and len(nodes) > 0:
not X in Y
withX not in Y
.and nodes
will be enough to express 'list is not empty'The result:
I agree, actually rewrote that part completely. It skipped nodes when there were looping nodes within the loops.
ED: Due to the new logic I think it shouldn't be to hard to implement the points that have been out of scope. For the backwards solver that should only change how to search for innern loop nodes. But I'm not sure if I'd even like to have "setting attributes within loops" to be supported - doesn't make a lot of sense especially for nested loops.
@ -261,2 +373,3 @@
finally:
self.has_run = True
self.iterations -= 1
if self.iterations == 0:
To account for potential issues, change the comparison to
<= 0
. That could prevent some infinite loops in caseself.iterations
becomes negative.Thanks, moving out the execution would definitely clean this up. I also considered to add an
AbstractLoopNode
because the_get_innern_loop_nodes
method,_inputs
and_outputs
properties are not required for other nodes.Checkout
From your project repository, check out a new branch and test the changes.