I scripted my custom "layout all nodes" which respects fixed positions of "pinned" nodes. I was still struggling with the Network Editor’s "layout all" nodes. I liked it most of the times but sometimes I wanted some nodes (or branches) to stay where they were. The best solution I came with was this:
pin () :
Function to pin(unpin) selected node(s) to their position. I pin just one node in a branch (or single node, camera, light, ropnet) … sometimes the last "OUT", sometimes the first "Object merge"
getConnectedNodes (node, got)
Finds all the nodes that are connected (any number of upstream / downstream nodes or connections).
node_prefixes ()
Returns a list of prefixes that should be aligned as pairs, even if they are not interconnected. For more, see section network_kwargs
lay ()
1) finds all the pinned nodes and remembers their positions
2) does classic layoutChildren(), which gives nice layout to the separate branches
3) repositions the branches to their previously stored pins
4) as a bonus, it places chopnets next to appropriate channelsop (naming convention applies)
source code
the following code is maintained also on my github
thank you, great people, I couldn't do this without you.
import hou
import toolutils
import wf_selection
reload(wf_selection)
def pin () :
for node in hou.selectedNodes():
node.setGenericFlag(hou.nodeFlag.DisplayComment,False)
if node.comment() == "`" :
node.setComment("")
else:
node.setComment("`")
def getConnectedNodes(node,got):
iteration = []
inout = []
try:
inout += node.inputs()
except:
has_no_inputs = 1
try:
inout += node.outputs()
except:
has_no_outputs = 1
for n in inout:
if n not in got:
got.append(n)
iteration.append(n)
iteration += getConnectedNodes(n,got)
return iteration
def node_prefixes () :
node_prefixes = []
node_prefixes.append( 'mat' )
node_prefixes.append( 'MAT' )
node_prefixes.append( 'QQMAT' )
node_prefixes.append( 'chop' )
node_prefixes.append( 'CHOP' )
node_prefixes.append( 'QQCHOP' )
node_prefixes.append( 'ref' )
node_prefixes.append( 'REF' )
node_prefixes.append( 'QQREF' )
node_prefixes.append( 'pre' )
node_prefixes.append( 'PRE' )
node_prefixes.append( 'QQPRE' )
return node_prefixes
def lay () :
parm_pane = wf_selection.pane_linkGroup( hou.paneTabType.NetworkEditor )
containernode = parm_pane.currentNode().parent()
containerpath = containernode.path()
################################
######## the pins #########
################################
childrenArr = containernode.children()
pinStatesArr = []
pinNodesArr = []
positionsArr = []
# store all positions
for child in childrenArr:
pinned = 0
if child.comment() == "`" :
pinned = 1
pinNodesArr.append( child )
pinStatesArr.append( pinned )
positionsArr.append( child.position() )
# store pinned positions
for pinNode in pinNodesArr:
pos = pinNode.position()
comment = str(pos[0]) + "," + str(pos[1])
pinNode.setComment(comment)
# classic layoutChildren()
containernode.layoutChildren()
# reposition the branches
for pinNode in pinNodesArr:
pinpos = pinNode.comment()
pinpos = pinpos.split(",")
pinpos = [ float(pinpos[0]) , float(pinpos[1]) ]
allConnected = []
allConnected = getConnectedNodes(pinNode,allConnected)
pos = pinNode.position()
move = [ pinpos[0] - pos[0] , pinpos[1] - pos[1] ]
for connected in allConnected:
try:
connected.move(move)
except:
no_connected = 1
# cleanup
pinNode.setPosition(pinpos)
pinNode.setComment("`")
################################
####### dat to app ########
################################
# define offset
offsetx = 3
offsety = 0
prefixes = node_prefixes()
for prefix in prefixes :
name_dat = prefix + "dat_"
name_app = prefix + "app_"
dats = hou.node(containerpath).glob(name_dat+"*")
# for all
for dat in dats:
xxx,task = dat.name().split("_")
# appropriate channel node
path_dat = containerpath + "/" + name_dat + task
path_app = containerpath + "/" + name_app + task
node_dat = hou.node(path_dat)
node_app = hou.node(path_app)
# get pos
posx = node_app.position()[0] + offsetx
posy = node_app.position()[1] + offsety
# check collisions
tolerance = 1.0;
for check in containernode.children() :
distance = hou.Vector2.length(check.position()-hou.Vector2([posx,posy]))
# print distance
if distance < tolerance :
posx = posx - 2*offsetx
break
# set pos
if node_dat.comment() != "`" :
# typical dat node
node_dat.setPosition( [posx,posy] )
else :
# dat has custom pos, probably because it collided
# so dont move it
pass
# shape
node_dat.setUserData("nodeshape", "clipped_right")
node_app.setUserData("nodeshape", "clipped_left")