"""Socket endpoints and conservative curve footprints for placement and preview.""" from .flow import socket_links def socket_position(socket, positions, sizes): node = socket.node x, y = positions[node] if node.bl_idname == "NodeReroute": return x + 8, y - 8 return x + (sizes[node].width if socket.is_output else 0), y - sizes[node].sockets[socket] def link_endpoints(link, positions, sizes): start = socket_position(link.from_socket, positions, sizes) x, y = socket_position(link.to_socket, positions, sizes) if link.to_socket.is_multi_input: siblings = socket_links(link.to_socket) y -= (siblings.index(link) - (len(siblings) - 1) / 2) * 8 return start, (x, y) def curve_footprint(start, end): """Reserve eight convex hulls covering a horizontal-tangent Bezier curve.""" x1, y1 = start x2, y2 = end bend = max(40, abs(x2 - x1) * 0.42) curves = [(start, (x1 + bend, y1), (x2 - bend, y2), end)] for _ in range(3): divided = [] for points in curves: rows = [points] for _ in range(3): rows.append([((a[0] + b[0]) / 2, (a[1] + b[1]) / 2) for a, b in zip(rows[-1], rows[-1][1:])]) divided.extend((tuple(row[0] for row in rows), tuple(row[-1] for row in reversed(rows)))) curves = divided return [(min(x for x, _ in curve), max(x for x, _ in curve), max(y for _, y in curve), min(y for _, y in curve)) for curve in curves]