fdd169bc35
Antes los hijos del mismo anchor se distribuian en un anillo de 360 grados alrededor del padre. Cuando un enricher producia 10+ hijos, se llenaban todas las direcciones y se pisaban nodos preexistentes. Ahora los hijos se reparten en un abanico de 45 grados (pi/4) saliendo del anchor en la direccion outward (vector anchor - centroide del resto del grafo). Si solo hay 1 nodo placed o coincide con el anchor, default a la derecha (0 rad). Capacidad por anillo restringida al arco (arc_span * r / min_dist), con fallback de subida de radio en mismo angulo si el slot ideal colisiona con un nodo no-orphan. Solo afecta la pasada 2 (orphans con anchor). Pasadas 1 y 3 intactas. build limpio, 102 pytest passed (WSL) + 91 passed/11 skipped (Windows). Refs: issues/0037-directional-orphan-placement.md
96 lines
3.4 KiB
Markdown
96 lines
3.4 KiB
Markdown
---
|
|
id: 0037
|
|
title: Placement direccional de orphans — abanico de 45 grados en una sola direccion
|
|
status: done
|
|
priority: high
|
|
created: 2026-05-04
|
|
completed: 2026-05-03
|
|
---
|
|
|
|
## Contexto
|
|
|
|
Hoy `place_orphans_near_neighbors` (en `main.cpp`) reparte los hijos del
|
|
mismo anchor en un anillo de 360 grados alrededor del padre. Resultado:
|
|
con muchos hijos, el viewport se llena en todas las direcciones,
|
|
pisando nodos preexistentes y dificultando la lectura del grafo.
|
|
|
|
Issue 0035 ya cluster los hijos del mismo anchor (no los desperdiga
|
|
por anillos crecientes), pero siguen ocupando 360 grados.
|
|
|
|
## Objetivo
|
|
|
|
Que los nuevos hijos creados por un enricher (orphans con un anchor
|
|
detectado por `layout_first_placed_neighbor`) se desplieguen en un
|
|
**abanico de 45 grados** (no 360) en UNA sola direccion saliendo del
|
|
anchor. Asi el grafo "crece" en una direccion clara por cada
|
|
ejecucion de enricher, sin pisar lo existente.
|
|
|
|
## Diseño
|
|
|
|
### 1. Direccion del abanico — outward por defecto
|
|
|
|
Para cada anchor con orphans:
|
|
- Calcular el centroide del resto de nodos placed del grafo (excluyendo
|
|
los orphans propios y el anchor).
|
|
- La direccion outward es el vector `anchor - centroide`, normalizado.
|
|
- Si solo hay 1 nodo en el grafo (el propio anchor) o el centroide
|
|
coincide con el anchor: usar direccion `(1, 0)` (derecha).
|
|
|
|
### 2. Reparto en abanico de 45 grados
|
|
|
|
`arc_span = π / 4` (45 grados, configurable como constante).
|
|
|
|
Para los N orphans del anchor:
|
|
- Si `N == 1`: lo plantamos exactamente en la direccion outward al
|
|
radio base (~80 px).
|
|
- Si `N <= 8` (capacidad del primer anillo en 45 grados con min_dist):
|
|
se reparten equiespaciados en el arco a un radio fijo.
|
|
- Si `N > 8`: se llenan anillos sucesivos del mismo arco con radios
|
|
crecientes (`80, 140, 200, 280, 400`) y misma capacidad por anillo.
|
|
|
|
Cada slot dentro del arco tiene angulo:
|
|
```
|
|
angle = out_angle - arc_span/2 + slot * (arc_span / (slot_count - 1))
|
|
```
|
|
(ajusta para cuando `slot_count == 1` para no dividir entre cero).
|
|
|
|
### 3. Colision con nodos preexistentes
|
|
|
|
Despues de calcular `(px, py)` para cada hijo, si colisiona con un
|
|
nodo no-orphan, incrementar el indice de anillo (mismo angulo,
|
|
radio mayor) hasta encontrar hueco o agotar anillos. En el ultimo
|
|
recurso aceptar solape — coherente con la logica actual.
|
|
|
|
### 4. Fallback sin anchor
|
|
|
|
Los orphans sin anchor (no tienen vecino placed) siguen el camino
|
|
existente: ring placement alrededor de la camara o parking lot.
|
|
NO se les aplica el abanico.
|
|
|
|
## Acceptance criteria
|
|
|
|
- Lanzar `split_words` (≥50 palabras unicas) sobre un nodo `text`:
|
|
los 10 sueltos del preview + 1 Group caen en un abanico de 45
|
|
grados saliendo del nodo `text`, en la direccion alejada del
|
|
resto del grafo.
|
|
- Lanzar el mismo enricher otra vez sobre OTRO nodo en otra
|
|
posicion: el abanico nuevo apunta hacia su propia direccion
|
|
outward.
|
|
- Si el grafo solo tiene 1 nodo (sin existing centroide), el
|
|
abanico sale a la derecha por default.
|
|
- Tests pytest siguen verdes (no requiere tests nuevos — el cambio
|
|
es algoritmico y se valida visualmente; opcional anyadir un test
|
|
C++ standalone que verifique angulos contra una fixture).
|
|
|
|
## TBD
|
|
|
|
Branch `issue/0037-directional-orphan-placement`, merge `--no-ff` a
|
|
master.
|
|
|
|
## Out of scope
|
|
|
|
- Animar la transicion del placement (poof-in suave). Fase 2.
|
|
- Layout interno del Group cuando se expande — sigue siendo todos
|
|
los hijos del Group ocultos en colapsado.
|
|
- Grouping logic (eso es 0035, ya cerrado fase 1).
|