Source code for fury.network.core

"""Network actors."""

import numpy as np

from fury.actor import Actor, Line
from fury.geometry import Geometry, buffer_to_geometry
from fury.lib import (
    Buffer,
    PointsShader,
    WorldObject,
    register_wgpu_render_function,
)
from fury.material import LineMaterial, NetworkMaterial
from fury.shader import NetworkComputeShader


[docs] class Network(WorldObject, Actor): """ Network actor that simulates force-directed layout on the GPU. Parameters ---------- nodes : ndarray, shape (N, 3) Initial positions of the nodes. edges : ndarray, shape (M, 2) Indices of connected nodes. colors : ndarray, shape (N, 4), optional Colors of the nodes. k : float, optional Optimal distance constant (affects equilibrium length). damping : float, optional Damping factor for velocity (0.0 to 1.0). repulsion_strength : float, optional Multiplier for repulsive forces. speed : float, optional Simulation speed factor. point_size : float, optional Size of the rendered nodes. edge_opacity : float, optional Opacity of the edges (0.0 to 1.0). """
[docs] def __init__( self, nodes, edges, colors=None, k=10.0, damping=0.9, repulsion_strength=1.0, speed=1.0, point_size=15.0, edge_opacity=0.5, ): """ Initialize the network actor instance. Parameters ---------- nodes : ndarray, shape (N, 3) Initial positions of the nodes. edges : ndarray, shape (M, 2) Indices of connected nodes. colors : ndarray, shape (N, 4), optional Colors of the nodes. k : float, optional Optimal distance constant (affects equilibrium length). damping : float, optional Damping factor for velocity (0.0 to 1.0). repulsion_strength : float, optional Multiplier for repulsive forces. speed : float, optional Simulation speed factor. point_size : float, optional Size of the rendered nodes. edge_opacity : float, optional Opacity of the edges (0.0 to 1.0). """ super().__init__() if not isinstance(nodes, np.ndarray) or nodes.ndim != 2 or nodes.shape[1] != 3: raise ValueError("nodes must be a (N, 3) numpy array") if not isinstance(edges, np.ndarray) or edges.ndim != 2 or edges.shape[1] != 2: raise ValueError("edges must be a (M, 2) numpy array") if np.any(edges < 0): raise ValueError( f"edges cannot contain negative indices. \ Found minimum value: {np.min(edges)}" ) self.n_nodes = nodes.shape[0] if np.any(edges >= self.n_nodes): raise ValueError( f"edges cannot contain indices >= number of nodes ({self.n_nodes}). \ Found maximum value: {np.max(edges)}" ) self.n_edges = edges.shape[0] velocities_data = np.zeros((self.n_nodes, 4), dtype=np.float32) adj = [[] for _ in range(self.n_nodes)] for u, v in edges: adj[u].append(v) adj[v].append(u) flat_adj = [] offsets = np.zeros(self.n_nodes, dtype=np.int32) counts = np.zeros(self.n_nodes, dtype=np.int32) current_offset = 0 for i in range(self.n_nodes): neighbors = adj[i] offsets[i] = current_offset counts[i] = len(neighbors) flat_adj.extend(neighbors) current_offset += len(neighbors) flat_adj = np.array(flat_adj, dtype=np.int32) if colors is None: colors = np.ones((self.n_nodes, 4), dtype=np.float32) self.geometry = buffer_to_geometry( positions=nodes.astype(np.float32), colors=colors.astype(np.float32), ) self.velocities_buffer = Buffer(velocities_data) self.adj_buffer = Buffer(flat_adj) self.offsets_buffer = Buffer(offsets) self.counts_buffer = Buffer(counts) self.material = NetworkMaterial( k=k, damping=damping, repulsion_strength=repulsion_strength, speed=speed, size=point_size, color_mode="vertex", ) edge_geometry = Geometry() edge_geometry.positions = self.geometry.positions edge_geometry.indices = Buffer(edges.astype(np.int32).ravel()) edge_material = LineMaterial( color=np.array([1.0, 1.0, 1.0, edge_opacity], dtype=np.float32), opacity=edge_opacity, ) edge_actor = Line(edge_geometry, edge_material) self.add(edge_actor)
[docs] @register_wgpu_render_function(Network, NetworkMaterial) def register_network_shaders(wobject): """ Register and return compute and rendering shader steps for the actor pipeline. Parameters ---------- wobject : Network The target network object component context. Returns ------- tuple The configured compute shader and render shader pair layout tuple. """ compute_shader = NetworkComputeShader(wobject) render_shader = PointsShader(wobject) return compute_shader, render_shader