feat(cpp/viz): split orphan TUs as separate fn entries (ADR 0003)
Cuando una funcion del registry parte su .cpp en varios TUs por testabilidad o separacion ImGui-vs-puro, cada TU adicional se registra como entrada propia con su .md en lugar de extender file_path para listar varios archivos. Aplicado a: - graph_labels_select_cpp_viz: helpers puros (compute_degrees + labels_select). - graph_viewport_selection_cpp_viz: clear/add/toggle/is_selected puros. - graph_types_cpp_viz: TU de update_bounds + find_node_by_user_data. graph_labels y graph_viewport actualizados para declarar las nuevas entradas en uses_functions. Razon detallada en docs/adr/0003 + regla actualizada en .claude/rules/uses_functions.md. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
---
|
||||
name: graph_labels_select
|
||||
kind: function
|
||||
lang: cpp
|
||||
domain: viz
|
||||
version: "1.0.0"
|
||||
purity: pure
|
||||
signature: "void graph::graph_compute_degrees(const GraphData& g, int* out_degrees); int graph::graph_labels_select(const GraphData& g, const LabelPolicy& p, float cam_x, float cam_y, float zoom, float widget_w, float widget_h, const int* degrees, int* out_indices, int out_capacity)"
|
||||
description: "Helpers puros (sin ImGui ni OpenGL) que calculan los nodos a etiquetar cada frame: graph_compute_degrees calcula el grado por nodo (solo aristas EF_VISIBLE), graph_labels_select aplica frustum cull + always_for_* + top-N por (size * (degree+1)) sobre min_node_pixel_size."
|
||||
tags: [graph, labels, pure, culling, top-n, frustum, testable]
|
||||
uses_functions: []
|
||||
uses_types: ["GraphData_cpp_viz"]
|
||||
returns: []
|
||||
returns_optional: false
|
||||
error_type: ""
|
||||
imports: []
|
||||
tested: true
|
||||
tests: ["select respects max_visible cap", "min_node_pixel_size culling", "always_for_selected gates by viewport", "no callback / empty graph no-op"]
|
||||
test_file_path: "cpp/tests/test_graph_labels.cpp"
|
||||
file_path: "cpp/functions/viz/graph_labels_select.cpp"
|
||||
framework: imgui
|
||||
params:
|
||||
- name: g
|
||||
desc: "Grafo a procesar (lectura). Se respetan NF_VISIBLE, NF_SELECTED, NF_HOVERED, NF_PINNED, EF_VISIBLE."
|
||||
- name: out_degrees
|
||||
desc: "(compute_degrees) Array de tamaño node_count que recibe el grado por nodo. Cuenta solo aristas con EF_VISIBLE."
|
||||
- name: p
|
||||
desc: "LabelPolicy: max_visible (top-N), always_for_*, min_zoom_for_all, min_node_pixel_size."
|
||||
- name: cam_x
|
||||
desc: "Centro de la camara en world coords (X)."
|
||||
- name: cam_y
|
||||
desc: "Centro de la camara en world coords (Y)."
|
||||
- name: zoom
|
||||
desc: "Pixels por unidad world. zoom <= 0 → no-op."
|
||||
- name: widget_w
|
||||
desc: "Ancho del widget en pixeles."
|
||||
- name: widget_h
|
||||
desc: "Alto del widget en pixeles."
|
||||
- name: degrees
|
||||
desc: "Array de tamaño node_count con el grado por nodo. NULL → score = size sin factor degree."
|
||||
- name: out_indices
|
||||
desc: "Array de salida con los indices de nodos a etiquetar. Capacidad = out_capacity."
|
||||
- name: out_capacity
|
||||
desc: "Capacidad maxima de out_indices. La funcion no escribe mas alla."
|
||||
output: "graph_compute_degrees: void. graph_labels_select: numero de indices escritos en out_indices. Cap duro = max_visible + |always_*|."
|
||||
notes: "Issue 0049j. TU separado de graph_labels.cpp para que los tests unitarios puedan cubrir la seleccion de candidatos sin pintar nada (graph_labels.cpp depende de ImGui). Estrategia: (A) nodos always_* en viewport sin chequeo de pixel size; (B) resto de nodos visibles que cumplen min_node_pixel_size, capados al top-N por (size * (degree+1)). Off-screen always_* se OMITEN intencionadamente. El degree se puede precalcular (O(E)) y pasar al select para evitar recomputar."
|
||||
---
|
||||
|
||||
# graph_labels_select
|
||||
|
||||
Logica pura de seleccion de etiquetas para `graph_labels`. Vive en su propio TU
|
||||
(`graph_labels_select.cpp`) — separada de `graph_labels.cpp` (que tiene la parte
|
||||
de pintado con ImGui) — para que los tests unitarios puedan ejercerla sin abrir
|
||||
una ventana.
|
||||
|
||||
## API
|
||||
|
||||
```cpp
|
||||
namespace graph {
|
||||
// Grado por nodo (cuenta solo aristas EF_VISIBLE). O(E).
|
||||
void graph_compute_degrees(const GraphData& g, int* out_degrees);
|
||||
|
||||
// Devuelve los indices de los nodos a etiquetar este frame.
|
||||
// O(N) frustum cull + O(K log K) si K candidatos > max_visible.
|
||||
int graph_labels_select(const GraphData& g, const LabelPolicy& p,
|
||||
float cam_x, float cam_y, float zoom,
|
||||
float widget_w, float widget_h,
|
||||
const int* degrees,
|
||||
int* out_indices, int out_capacity);
|
||||
}
|
||||
```
|
||||
|
||||
## Composabilidad
|
||||
|
||||
- Lo usa `graph_labels_draw` y `graph_labels_draw_at` internamente cada frame.
|
||||
- Una app puede llamarlo directamente para pintar etiquetas con su propio
|
||||
renderer (no-ImGui) reusando la misma politica.
|
||||
- Sin dependencias de ImGui ni OpenGL — puro `<algorithm>` + `<vector>`.
|
||||
|
||||
## Estrategia (resumen)
|
||||
|
||||
1. **Pase A — always_***: nodos selected/hovered/pinned visibles en viewport.
|
||||
Skip de `min_node_pixel_size`. Off-screen NO entra (decision documentada).
|
||||
2. **Pase B — top-N**: del resto de nodos visibles en viewport con
|
||||
`size * zoom >= min_node_pixel_size`, ordena por `score = size * (degree+1)`
|
||||
y coge los `max_visible` primeros (`std::partial_sort`).
|
||||
3. **Cap duro**: `max_visible + |always_*|`. Imposible saltarse — si quieres 0
|
||||
labels excepto always, pon `max_visible = 0`.
|
||||
|
||||
## Tests
|
||||
|
||||
Cubiertos en `cpp/tests/test_graph_labels.cpp`. La funcion devuelve int sin
|
||||
tocar ImGui — pasable a `assert(graph_labels_select(...) == N)`.
|
||||
Reference in New Issue
Block a user