2022-12-01 07:37:35 -05:00
import bpy
import typing
2023-11-16 16:25:59 -05:00
from collections import deque , Counter
2022-12-01 07:37:35 -05:00
def _arrange ( node_tree , padding : typing . Tuple [ float , float ] = ( 50 , 25 ) ) :
# Organize the nodes into columns based on their links.
columns : typing . List [ typing . List [ typing . Any ] ] = [ ]
2023-11-14 19:11:57 -05:00
def topo_sort ( graph ) :
in_degree = { u : 0 for u in graph }
for u in graph :
for v in graph [ u ] :
in_degree [ v ] + = 1
queue = deque ( [ u for u in in_degree if in_degree [ u ] == 0 ] )
topo_order = [ ]
while queue :
u = queue . popleft ( )
topo_order . append ( u )
for v in graph [ u ] :
in_degree [ v ] - = 1
if in_degree [ v ] == 0 :
queue . append ( v )
return topo_order
graph = { node : set ( ) for node in node_tree . nodes }
2023-11-16 16:25:59 -05:00
node_input_link_count = Counter ( )
2023-11-14 19:11:57 -05:00
for link in node_tree . links :
graph [ link . from_node ] . add ( link . to_node )
2023-11-15 19:32:37 -05:00
node_input_link_count [ link . to_socket ] + = 1
2023-11-14 19:11:57 -05:00
sorted_nodes = topo_sort ( graph )
column_index = { }
for node in reversed ( sorted_nodes ) :
2023-11-15 10:56:01 -05:00
column_index [ node ] = max ( [ column_index [ adj_node ] for adj_node in graph [ node ] ] , default = - 1 ) + 1
2023-11-14 19:11:57 -05:00
if column_index [ node ] == len ( columns ) :
columns . append ( [ node ] )
2022-12-01 07:37:35 -05:00
else :
2023-11-14 19:11:57 -05:00
columns [ column_index [ node ] ] . append ( node )
columns = reversed ( columns )
2022-12-01 07:37:35 -05:00
# Arrange the columns, computing the size of the node manually so arrangement can be done without UI being visible.
UI_SCALE = bpy . context . preferences . view . ui_scale
NODE_HEADER_HEIGHT = 20
NODE_LINK_HEIGHT = 28
NODE_PROPERTY_HEIGHT = 28
NODE_VECTOR_HEIGHT = 84
x = 0
for col in columns :
largest_width = 0
y = 0
for node in col :
node . update ( )
input_count = len ( list ( filter ( lambda i : i . enabled , node . inputs ) ) )
output_count = len ( list ( filter ( lambda i : i . enabled , node . outputs ) ) )
parent_props = [ prop . identifier for base in type ( node ) . __bases__ for prop in base . bl_rna . properties ]
properties_count = len ( [ prop for prop in node . bl_rna . properties if prop . identifier not in parent_props ] )
2023-11-15 19:32:37 -05:00
unset_vector_count = len ( list ( filter ( lambda i : i . enabled and i . type == ' VECTOR ' and node_input_link_count [ i ] == 0 , node . inputs ) ) )
2022-12-01 07:37:35 -05:00
node_height = (
NODE_HEADER_HEIGHT \
+ ( output_count * NODE_LINK_HEIGHT ) \
+ ( properties_count * NODE_PROPERTY_HEIGHT ) \
+ ( input_count * NODE_LINK_HEIGHT ) \
+ ( unset_vector_count * NODE_VECTOR_HEIGHT )
) * UI_SCALE
if node . width > largest_width :
largest_width = node . width
node . location = ( x , y )
y - = node_height + padding [ 1 ]
x + = largest_width + padding [ 0 ]