Files
blender-portable-repo/scripts/addons/NodeRelax-Blender-Addon/operators/utils.py
T
2026-03-17 14:58:51 -06:00

224 lines
6.6 KiB
Python

import mathutils
MOVE_UNIT = 1
def global_loc(node):
if node.parent:
return global_loc(node.parent) + node.location
else:
return node.location
def calc_node(node, nodes, influence, slide_vec, relax_power, collide_power, collide_dist, pull_non_siblings):
if node.type == 'FRAME':
return False
loc = global_loc(node)
size = node.dimensions
offset = mathutils.Vector(slide_vec)
if relax_power > 0:
# Relax
tar_y = 0
link_cnt = 0
tar_x_in = loc.x
has_input = False
for socket in node.inputs: # Input links
for link in socket.links:
other = link.from_node
if not pull_non_siblings and node.parent != other.parent:
continue
loc_other = global_loc(other)
size_other = other.dimensions
x = loc_other.x + size_other.x + collide_dist.x
if has_input > 0:
tar_x_in = max(tar_x_in, x)
else:
tar_x_in = x
has_input = True
tar_y += loc_other.y - size_other.y / 2
link_cnt += 1
tar_x_out = loc.x
has_output = False
for socket in node.outputs: # Output links
for link in socket.links:
other = link.to_node
if not pull_non_siblings and node.parent != other.parent:
continue
loc_other = global_loc(other)
size_other = other.dimensions
x = loc_other.x - size.x - collide_dist.x
if has_output > 0:
tar_x_out = min(tar_x_out, x)
else:
tar_x_out = x
has_output = True
tar_y += loc_other.y - size_other.y / 2
link_cnt += 1
if link_cnt > 0:
tar_x = tar_x_in * int(has_input) + tar_x_out * int(has_output)
tar_x /= int(has_input) + int(has_output)
tar_y /= link_cnt
tar_y += size.y / 2
offset.x += (tar_x - loc.x) * relax_power
offset.y += (tar_y - loc.y) * relax_power
if collide_power > 0:
# Collision
for other in nodes:
if other == node:
continue
if other.type == 'FRAME':
continue
collide(loc, global_loc(other), size, other.dimensions,
offset, collide_power, collide_dist)
if abs(offset.x) > MOVE_UNIT or abs(offset.y) > MOVE_UNIT:
node.location += offset * influence
return True
else:
return False
def socket_pos(socket, sockets, size):
i = 0
sockets_filtered = []
for s in sockets:
if len(s.links) > 0:
sockets_filtered.append(s)
for s in sockets_filtered:
if s == socket:
return (i / len(sockets_filtered)) * size
i += 1
return size / 2
def calc_collision_y(node, nodes, collide_power, collide_dist):
if node.type == 'FRAME':
return False
loc = global_loc(node)
size = node.dimensions
offset = mathutils.Vector((0, 0))
# Collision
for other in nodes:
if other == node:
continue
if other.type == 'FRAME':
continue
collide(loc, global_loc(other), size, other.dimensions,
offset, 1, collide_dist, True)
if abs(offset.y) > MOVE_UNIT:
node.location += offset * collide_power
return True
else:
return False
def arrange_relax(node, influence, relax_power, distance, clamped_pull):
if node.type == 'FRAME':
return False
loc = global_loc(node)
size = node.dimensions
offset = mathutils.Vector((0, 0))
# Relax
tar_y = 0
tar_x_in = loc.x if clamped_pull else 0
link_cnt = 0
has_input = False
for socket in node.inputs: # Input links
for link in socket.links:
other = link.from_node
# if node.parent != other.parent: continue
loc_other = global_loc(other)
size_other = other.dimensions
x = loc_other.x + size_other.x + distance
if clamped_pull:
if has_input > 0:
tar_x_in = max(tar_x_in, x)
else:
tar_x_in = x
else:
tar_x_in += x
has_input = True
tar_y += loc_other.y + socket_pos(socket, node.inputs, size.y) - socket_pos(link.from_socket, other.outputs,
size_other.y)
link_cnt += 1
tar_x_out = loc.x if clamped_pull else 0
has_output = False
for socket in node.outputs: # Output links
for link in socket.links:
other = link.to_node
# if node.parent != other.parent: continue
loc_other = global_loc(other)
size_other = other.dimensions
x = loc_other.x - size.x - distance
if clamped_pull:
if has_output > 0:
tar_x_out = min(tar_x_out, x)
else:
tar_x_out = x
else:
tar_x_out += x
has_output = True
tar_y += loc_other.y + socket_pos(socket, node.outputs, size.y) - socket_pos(link.to_socket, other.inputs,
size_other.y)
link_cnt += 1
if link_cnt > 0:
if clamped_pull:
tar_x = tar_x_in * int(has_input) + tar_x_out * int(has_output)
tar_x /= int(has_input) + int(has_output)
else:
tar_x = (tar_x_in + tar_x_out) / link_cnt
tar_y /= link_cnt
offset.x += (tar_x - loc.x) * relax_power
offset.y += (tar_y - loc.y) * relax_power
if abs(offset.x) > MOVE_UNIT or abs(offset.y) > MOVE_UNIT:
node.location += offset * influence
return True
else:
return False
def collide(loc0, loc1, size0, size1, offset, power, dist, only_y=False):
pos0 = loc0 + size0 / 2
pos1 = loc1 + size1 / 2
pos0.y -= size0.y
pos1.y -= size1.y
size = (size0 + size1) / 2 + dist
delta = pos1 - pos0
inters = size - mathutils.Vector((abs(delta.x), abs(delta.y)))
if inters.x > 0 and inters.y > 0:
if inters.y < inters.x or only_y:
if delta.y > 0:
inters.y *= -1
offset.y += inters.y / 2 * power
else:
if delta.x > 0:
inters.x *= -1
offset.x += inters.x / 2 * power