---
name: graph_layouts
kind: function
lang: cpp
domain: viz
version: "1.0.0"
purity: pure
signature: "void graph::layout_grid(GraphData&, float spacing); void graph::layout_circular(GraphData&, float radius); void graph::layout_random(GraphData&, float spread); void graph::layout_radial(GraphData&, int root_node, float ring_spacing); void graph::layout_hierarchical(GraphData&, int direction, float layer_spacing, float node_spacing); void graph::layout_fixed(GraphData&)"
description: "Conjunto de layouts estaticos (no iterativos) para GraphData: grid, circular, random, radial, hierarchical (Sugiyama heuristico), fixed. Todos respetan NF_PINNED."
tags: [graph, layout, static, radial, hierarchical, sugiyama, osint]
uses_functions: []
uses_types: ["GraphData_cpp_viz"]
returns: []
returns_optional: false
error_type: ""
imports: []
tested: true
tests: ["grid centers and respects pin", "circular places on circle", "radial root at center, hop ring", "hierarchical levels by longest path", "fixed is no-op"]
test_file_path: "cpp/tests/test_graph_layouts.cpp"
file_path: "cpp/functions/viz/graph_layouts.cpp"
framework: imgui
params:
  - name: graph
    desc: "Referencia al grafo (GraphData) cuyos nodos se reposicionan in-place. Mutaciones: x, y, vx=0, vy=0 por nodo no pinned."
  - name: spacing
    desc: "(layout_grid) Distancia en world units entre celdas adyacentes de la cuadricula."
  - name: radius
    desc: "(layout_circular) Radio del circulo unico en world units."
  - name: spread
    desc: "(layout_random) Mitad del lado del cuadrado en el que se distribuyen aleatoriamente las posiciones (rango [-spread, spread])."
  - name: root_node
    desc: "(layout_radial) Indice del nodo raiz. BFS desde aqui asigna el hop. Si es invalido, usa 0."
  - name: ring_spacing
    desc: "(layout_radial) Distancia radial entre anillos de hops consecutivos."
  - name: direction
    desc: "(layout_hierarchical) Orientacion: 0=LR (left->right), 1=RL, 2=TB (top->bottom), 3=BT."
  - name: layer_spacing
    desc: "(layout_hierarchical) Distancia entre niveles consecutivos en el eje del layout."
  - name: node_spacing
    desc: "(layout_hierarchical) Distancia entre nodos del mismo nivel en el eje transversal."
output: "Ninguno (void). Los nodos no pinned se mueven in-place; nodos con NF_PINNED conservan posicion y velocidad."
notes: "Issue 0049i. layout_circular/layout_grid migrados desde graph_force_layout.cpp; los wrappers deprecados graph_layout_circular/graph_layout_grid siguen funcionando como compat hasta cierre de 0049."
---

# graph_layouts

Funciones de layout estatico (instantaneo, sin iterar). Todas escriben las
posiciones de los nodos no pinned y cero las velocidades; los nodos con
`NF_PINNED` no se tocan. Util para inicializar un grafo antes del force layout
o para ofrecer alternativas de visualizacion en TUIs OSINT.

## API

```cpp
namespace graph {
    void layout_grid       (GraphData&, float spacing = 20.0f);
    void layout_circular   (GraphData&, float radius  = 100.0f);
    void layout_random     (GraphData&, float spread  = 200.0f);
    void layout_radial     (GraphData&, int root_node = 0,
                                       float ring_spacing = 80.0f);
    void layout_hierarchical(GraphData&, int direction = 0,
                                        float layer_spacing = 120.0f,
                                        float node_spacing  = 60.0f);
    void layout_fixed      (GraphData&);  // no-op
}
```

## Algoritmos

### `layout_grid`
Cuadricula uniforme. `cols = ceil(sqrt(N))`, `rows = ceil(N/cols)`. Centro del
grafo en `(0,0)`.

### `layout_circular`
Circulo unico. Cada nodo en el angulo `2*pi*i/N`.

### `layout_random`
Posiciones uniformes en `[-spread, spread]^2`. Usa `rand()` — llamar
`srand(seed)` antes para reproducibilidad.

### `layout_radial`
BFS no dirigido desde `root_node`. Cada hop `k` se coloca en un circulo de
radio `k * ring_spacing`. Nodos del mismo hop se distribuyen uniformemente
en su circulo. Las componentes desconectadas van a un anillo extra al final.
Util para vistas de "vecinos a N saltos" tipicas en OSINT.

### `layout_hierarchical`
Sugiyama-style heuristico:
1. Niveles por longest-path BFS desde nodos sin in-edges.
2. Reduccion de cruces greedy: cada nivel `L>0` se reordena por el baricentro
   de los indices de sus padres en el nivel `L-1`.
3. Posiciones: el nivel define el eje principal (X o Y segun `direction`),
   los nodos dentro del nivel se centran en el eje transversal.

No es Sugiyama optimo (eso es un problema NP-hard). Es suficientemente bueno
para grafos OSINT pequenios/medianos: jerarquias `Person -> Email -> Domain`,
arboles de dependencia, etc.

### `layout_fixed`
No-op. Se mantiene en el conjunto para que un caller pueda escribir un switch
que cubra todos los modos sin un caso especial.

## Composicion con graph_force_layout

Tipico: layout estatico inicial -> force-directed para refinar.

```cpp
graph::layout_circular(g, 200.0f);   // arranque uniforme
ForceLayoutConfig cfg;
for (int i = 0; i < 300; ++i) {
    graph_force_layout_step(g, cfg);
}
```

Para grafos jerarquicos donde no se quiere que el force layout deshaga la
estructura: pinnar nodos clave (`NF_PINNED`) tras `layout_hierarchical` y
dejar que el force solo refine los del medio.

## Notas

- Wrappers deprecados: `graph_layout_circular` y `graph_layout_grid` siguen en
  `graph_force_layout.h` y delegan aqui. Codigo nuevo debe usar el namespace
  `graph::`.
- `layout_radial` y `layout_hierarchical` construyen una lista de adyacencia
  temporal `O(V+E)` por llamada. Para grafos enormes (>>1M aristas) considerar
  cachear la adyacencia entre llamadas.
