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>
8.0 KiB
name, kind, lang, domain, version, purity, signature, description, tags, uses_functions, uses_types, returns, returns_optional, error_type, imports, tested, tests, test_file_path, file_path, framework, params, output, notes
| name | kind | lang | domain | version | purity | signature | description | tags | uses_functions | uses_types | returns | returns_optional | error_type | imports | tested | tests | test_file_path | file_path | framework | params | output | notes | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| graph_labels | function | cpp | viz | 1.0.0 | impure | void graph::graph_labels_draw(const GraphData&, const GraphViewportState&, const LabelPolicy&, GetLabelFn, void*); void graph::graph_labels_draw_at(const GraphData&, float cam_x, float cam_y, float zoom, float wmin_x, float wmin_y, float w, float h, const LabelPolicy&, GetLabelFn, void*) | Renderiza etiquetas de nodos sobre el viewport del grafo via ImDrawList con politica configurable: always-on para selected/hovered/pinned, top-N por (size * (degree+1)), y culling por viewport + min pixel size. Independiente del renderer GPU. |
|
|
|
false | error_go_core |
|
true |
|
cpp/tests/test_graph_labels.cpp | cpp/functions/viz/graph_labels.cpp | imgui |
|
Ninguno (void) salvo graph_labels_select que devuelve int (numero de indices escritos en out_indices). Las funciones draw pintan rectangulos y texto via ImDrawList del current ImGui window. | Issue 0049j. La estrategia de seleccion es: (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 para no spamear. El degree se calcula on-the-fly cada frame en draw_at (O(E)); para hot paths el caller puede precalcular y pasarlo a graph_labels_select. Cap duro = max_visible + |always_*|. |
graph_labels
Pintar etiquetas de nodos sobre la imagen del FBO del graph_renderer. Pensado
para uso OSINT/Maltego: necesitas leer "juan@x.com", IBAN, etc. en los nodos
relevantes, pero no puedes mostrar 20k labels — el ojo y la GPU se saturan.
Estrategia
Cada frame el algoritmo decide que nodos etiquetar:
- Always-on — si
LabelPolicy.always_for_{selected,hovered,pinned}esta activo y el nodo lleva ese flag, se etiqueta. Skip demin_node_pixel_size, pero sigue requiriendo estar dentro del viewport (decision: off-screen no se dibuja para no spamear con flechas o etiquetas en los bordes). - Top-N — del resto de nodos visibles en el viewport que ademas tienen
size * zoom >= min_node_pixel_size, se ordena porscore = size * (degree+1)y se cogen losmax_visibleprimeros. - Cap duro — total =
max_visible + |always_*|. Sin opciones de saltarse esto. Si el caller quiere 0 labels excepto los always, basta ponermax_visible = 0.
min_zoom_for_all esta en la struct por compatibilidad con el spec original;
en la implementacion v1 actua como un parametro suave: con zoom alto la mayoria
de nodos visibles superan min_node_pixel_size y entran al top-N por si solos,
asi que el efecto deseado (mostrar todos a zoom alto) sale naturalmente sin
ramas adicionales.
API
namespace graph {
struct LabelPolicy { /* ... */ };
typedef const char* (*GetLabelFn)(int node_idx, void* user);
// Tras ImGui::Image(...) o graph_viewport(...). Resuelve rect via
// GetItemRectMin/Max y usa el ImDrawList del current window.
void graph_labels_draw (const GraphData&, const GraphViewportState&,
const LabelPolicy&, GetLabelFn, void*);
// Variante explicita: el caller pasa cam, zoom y rect del widget.
void graph_labels_draw_at(const GraphData&,
float cam_x, float cam_y, float zoom,
float wmin_x, float wmin_y,
float w, float h,
const LabelPolicy&, GetLabelFn, void*);
// Helpers puros (testables sin ImGui).
void graph_compute_degrees(const GraphData&, int* out_degrees);
int graph_labels_select (const GraphData&, const LabelPolicy&,
float cam_x, float cam_y, float zoom,
float w, float h,
const int* degrees,
int* out_indices, int out_capacity);
}
Uso tipico (en demos_graph)
graph_viewport("##g", graph, state, ImVec2(0, 460));
graph::LabelPolicy policy;
policy.max_visible = 200;
policy.always_for_selected = true;
policy.always_for_hovered = true;
policy.min_node_pixel_size = 12.0f;
struct LabelCtx { char buf[32]; };
auto get_label = [](int idx, void* user) -> const char* {
auto* ctx = (LabelCtx*)user;
std::snprintf(ctx->buf, sizeof(ctx->buf), "#%d", idx);
return ctx->buf;
};
LabelCtx ctx;
graph::graph_labels_draw(graph, state, policy, get_label, &ctx);
Coste
graph_compute_degrees: O(E).graph_labels_select: O(N) para frustum cull + O(K log K) si K candidatos superanmax_visible(partial_sort).- Por label: 1
AddRectFilled+ 1AddText. ImDrawList es eficiente; conmax_visible = 200apenas se nota.
Notas de integracion
- Llamar despues de
graph_viewport(oImGui::Imagedel FBO). El widget rect se resuelve conImGui::GetItemRectMin/Max(). - Las labels se dibujan en el
ImDrawListdel current window. Si el FBO esta dentro de unBeginChild/EndChild, el clip rect del child puede recortar etiquetas de nodos pegados a los bordes — usardraw_aty pasar el rect que se quiera respetar. - El callback se invoca como mucho una vez por nodo etiquetado por frame.
- Para reproducibilidad en tests, usar
graph_labels_selectcon un buffer de capacidad conocida — no toca ImGui.
Split de TU (2026-05-04, ADR 0003)
Los helpers puros graph_compute_degrees y graph_labels_select viven en
graph_labels_select.cpp y se indexan como entrada propia
graph_labels_select_cpp_viz. Esta entrada graph_labels.md solo cubre
graph_labels_draw y graph_labels_draw_at (impuras, dependen de ImGui).
Apps que reusan graph_labels deben enlazar AMBOS .cpp y declarar AMBAS
entradas en su app.md:
${FN_CPP_ROOT_DIR}/functions/viz/graph_labels.cpp
${FN_CPP_ROOT_DIR}/functions/viz/graph_labels_select.cpp
uses_functions:
- graph_labels_cpp_viz
- graph_labels_select_cpp_viz