Files
fn_registry/cpp/functions/viz/graph_labels.h
T
egutierrez 4b28ef6774 feat(viz): graph_labels render con LabelPolicy + ImDrawList (issue 0049j)
graph_labels_draw pinta etiquetas de nodos sobre el FBO del graph_renderer
via ImDrawList. Politica configurable: always-on para selected/hovered/
pinned, top-N por size*(degree+1), culling por viewport AABB y
min_node_pixel_size. Cap duro = max_visible + |always_*|.

API:
- graph_labels_draw(graph, viewport_state, policy, cb, user)
- graph_labels_draw_at(...)  — variante con rect explicito
- graph_labels_select(...)   — helper puro testeable
- graph_compute_degrees(...) — O(E)

Splitting en dos TUs:
- graph_labels.cpp          — funciones draw (depende de ImGui)
- graph_labels_select.cpp   — helpers puros para tests sin ImGui

12 tests en test_graph_labels (culling, max_visible cap, min_pixel_size,
always_* gating por viewport, top-N por score, edge cases). Todos verdes.

Integrado en demos_graph con UI: toggle Labels, sliders Max visible /
Font / Min px, checkboxes Selected/Hovered/Pinned. Golden de
graph_viewport regenerado.

Cierra issue 0049j.
2026-04-29 23:53:32 +02:00

66 lines
2.9 KiB
C++

#pragma once
#include <cstdint>
// Render de etiquetas de nodos sobre el viewport del grafo (issue 0049j).
// Independiente del renderer GPU: usa `ImDrawList` del current window y se
// compone sobre la imagen del FBO ya pintada por `graph_renderer`.
struct GraphData;
struct GraphViewportState;
namespace graph {
struct LabelPolicy {
bool always_for_selected = true;
bool always_for_hovered = true;
bool always_for_pinned = false;
int max_visible = 200; // top-N por size + degree
float min_zoom_for_all = 4.0f; // a este zoom, mostrar todos los visibles del viewport
float min_node_pixel_size = 12.0f; // skip si en pantalla mide menos
float font_size = 13.0f; // pixels
uint32_t color = 0xFFFFFFFF; // ABGR
uint32_t bg_color = 0xC8000000; // semi-transparente
float padding_x = 4.0f;
float padding_y = 2.0f;
};
// Callback que devuelve el texto del label dado un node_idx. El consumer
// maneja su propio string pool / metadata. Devolver NULL o "" omite el label.
typedef const char* (*GetLabelFn)(int node_idx, void* user);
// Llamar tras `ImGui::Image(...)` del FBO (o tras `graph_viewport`). Usa
// `ImGui::GetItemRectMin/Max()` para conocer el rect del widget y
// `ImGui::GetWindowDrawList()` para pintar.
void graph_labels_draw(const GraphData& graph, const GraphViewportState& state,
const LabelPolicy& policy, GetLabelFn cb, void* user);
// Variante sin ImGui state — util para tests y para callers que ya tienen
// el widget rect resuelto. Pinta sobre el ImDrawList del current window.
// `widget_min_x/y` y `widget_w/h` describen el rect del FBO en pantalla.
void graph_labels_draw_at(const GraphData& graph,
float cam_x, float cam_y, float zoom,
float widget_min_x, float widget_min_y,
float widget_w, float widget_h,
const LabelPolicy& policy,
GetLabelFn cb, void* user);
// --- Helpers puros (exportados para tests y callers avanzados) -----------
// Calcula el grado (numero de aristas incidentes) por nodo. El caller
// reserva `out_degrees` con tamano `graph.node_count`.
void graph_compute_degrees(const GraphData& graph, int* out_degrees);
// Selecciona los indices de nodos que deberian recibir label segun la
// politica. Funcion pura: no toca ImGui ni el grafo. Devuelve el numero de
// indices escritos en `out_indices` (capado a `out_capacity`).
//
// `degrees` puede ser NULL — en ese caso el score de top-N degrada a `size`
// (sin el factor degree+1).
int graph_labels_select(const GraphData& graph, const LabelPolicy& policy,
float cam_x, float cam_y, float zoom,
float widget_w, float widget_h,
const int* degrees,
int* out_indices, int out_capacity);
} // namespace graph