--- name: graph_force_layout kind: function lang: cpp domain: viz version: "1.0.0" purity: pure signature: "float graph_force_layout_step(GraphData& graph, const ForceLayoutConfig& config)" description: "Layout force-directed con aproximacion Barnes-Hut para grafos grandes, ejecuta un paso de simulacion por llamada" tags: [graph, layout, force-directed, barnes-hut, physics, gpu] uses_functions: [] uses_types: ["GraphData_cpp_viz"] returns: [] returns_optional: false error_type: "" imports: [] tested: false tests: [] test_file_path: "" file_path: "cpp/functions/viz/graph_force_layout.cpp" framework: imgui params: - name: graph desc: "Referencia al grafo (GraphData) cuyos nodos se actualizan in-place. Modifica x, y, vx, vy de cada nodo no pinned." - name: config desc: "Parametros de la simulacion: repulsion (fuerza coulombiana), attraction (spring constant), damping (decay de velocidad), theta (precision Barnes-Hut 0=exacto/1=rapido), gravity (atraccion al centro), max_velocity, iterations." output: "Energia cinetica total (suma de |v|^2). Cuando cae por debajo de un umbral elegido por el caller, el layout ha convergido y se puede dejar de llamar." --- # graph_force_layout Implementa el algoritmo de layout force-directed clasico (Fruchterman-Reingold / Eades) con aproximacion Barnes-Hut O(n log n) para escalar a grafos de miles de nodos. ## Algoritmo Cada llamada a `graph_force_layout_step` ejecuta `config.iterations` pasos. Un paso: 1. **Construccion del quadtree** (Barnes-Hut): se calcula el bounding box de las posiciones actuales, se construye un quadtree flat en `quad_pool` (sin allocaciones por nodo). Cada celda acumula centro de masa y masa total. 2. **Repulsion**: para cada nodo se recorre el quadtree. Si el cociente `cell_size / distance < theta`, la celda se trata como una sola masa puntual (multipolo de orden 0). Si no, se desciende a los hijos. Con `theta=0` es O(n²) exacto; con `theta=0.5` es O(n log n). 3. **Atraccion**: para cada arista `(s, t)`, fuerza de Hooke `F = k * dist * weight` en la direccion del arco. 4. **Gravedad**: fuerza proporcional a la distancia al origen, evita que el grafo derive fuera de pantalla. 5. **Integracion**: `v = v * damping + F`, `pos += v`, con clamping de velocidad. 6. Nodos con `pinned = true` no se mueven en ningun paso. ## Funciones auxiliares ```cpp // Randomizar posiciones para empezar la simulacion graph_force_layout_reset(graph, 200.0f); // Layout circular instantaneo (sin iteracion) graph_layout_circular(graph, 150.0f); // Layout en grid instantaneo graph_layout_grid(graph, 25.0f); ``` ## Ejemplo de uso tipico (loop ImGui) ```cpp static ForceLayoutConfig cfg; static bool running = true; if (running) { float energy = graph_force_layout_step(my_graph, cfg); if (energy < 0.01f) running = false; // convergido } ``` ## Notas de implementacion - El quadtree usa un pool estatico de `1 << 20` (~1M) celdas. Para grafos de >500K nodos se recomienda reducir `MAX_QUAD_NODES` o aumentarlo segun memoria disponible. - La pila de traversal en `quad_force` es tambien estatica (`static int stack[]`); no es thread-safe si se llama desde multiples hilos simultaneamente. - `graph_force_layout_reset` usa `rand()`. Para reproducibilidad llama `srand(seed)` antes. - Los buffers de fuerza (`fx_buf`, `fy_buf`) se realocan una sola vez cuando el conteo de nodos supera la capacidad previa; en el uso normal (tamano fijo) no hay allocaciones por frame.