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.
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
// Pintado de etiquetas via ImDrawList (issue 0049j). La logica de seleccion
|
||||
// de candidatos (frustum cull + top-N) vive en graph_labels_select.cpp para
|
||||
// que sea testeable sin enlazar ImGui.
|
||||
|
||||
#include "viz/graph_labels.h"
|
||||
#include "viz/graph_types.h"
|
||||
#include "viz/graph_viewport.h"
|
||||
|
||||
#include "imgui.h"
|
||||
|
||||
#include <cfloat>
|
||||
#include <vector>
|
||||
|
||||
namespace graph {
|
||||
|
||||
void graph_labels_draw_at(const GraphData& g,
|
||||
float cam_x, float cam_y, float zoom,
|
||||
float wmin_x, float wmin_y,
|
||||
float w, float h,
|
||||
const LabelPolicy& p,
|
||||
GetLabelFn cb, void* user)
|
||||
{
|
||||
if (!cb) return;
|
||||
if (g.node_count <= 0) return;
|
||||
if (w <= 0.0f || h <= 0.0f) return;
|
||||
|
||||
// Degrees on-the-fly: O(E) por frame. Cachear si se vuelve hot path.
|
||||
static thread_local std::vector<int> degrees;
|
||||
degrees.assign((size_t)g.node_count, 0);
|
||||
graph_compute_degrees(g, degrees.data());
|
||||
|
||||
// Cap duro: max_visible + |always_*|. |always_*| <= node_count.
|
||||
const int max_total = p.max_visible + g.node_count;
|
||||
static thread_local std::vector<int> indices;
|
||||
indices.resize((size_t)max_total);
|
||||
|
||||
const int n_labels = graph_labels_select(
|
||||
g, p, cam_x, cam_y, zoom, w, h,
|
||||
degrees.data(), indices.data(), max_total);
|
||||
if (n_labels <= 0) return;
|
||||
|
||||
ImDrawList* dl = ImGui::GetWindowDrawList();
|
||||
ImFont* font = ImGui::GetFont();
|
||||
if (!dl || !font) return;
|
||||
|
||||
const float cx = wmin_x + w * 0.5f;
|
||||
const float cy = wmin_y + h * 0.5f;
|
||||
|
||||
for (int k = 0; k < n_labels; ++k) {
|
||||
const int idx = indices[k];
|
||||
const GraphNode& n = g.nodes[idx];
|
||||
const char* text = cb(idx, user);
|
||||
if (!text || !*text) continue;
|
||||
|
||||
const float vx = (n.x - cam_x) * zoom + cx;
|
||||
const float vy = (n.y - cam_y) * zoom + cy;
|
||||
|
||||
const float node_px = resolve_node_size(n, g.types, g.type_count) * zoom;
|
||||
const float ox = node_px * 0.5f + p.padding_x;
|
||||
const float oy = -p.font_size * 0.5f;
|
||||
|
||||
const ImVec2 ts = font->CalcTextSizeA(p.font_size, FLT_MAX, 0.0f, text);
|
||||
const ImVec2 a(vx + ox - p.padding_x, vy + oy - p.padding_y);
|
||||
const ImVec2 b(vx + ox + ts.x + p.padding_x, vy + oy + ts.y + p.padding_y);
|
||||
|
||||
dl->AddRectFilled(a, b, p.bg_color, 2.0f);
|
||||
dl->AddText(font, p.font_size, ImVec2(vx + ox, vy + oy),
|
||||
p.color, text);
|
||||
}
|
||||
}
|
||||
|
||||
void graph_labels_draw(const GraphData& g, const GraphViewportState& s,
|
||||
const LabelPolicy& p, GetLabelFn cb, void* user)
|
||||
{
|
||||
const ImVec2 wmin = ImGui::GetItemRectMin();
|
||||
const ImVec2 wmax = ImGui::GetItemRectMax();
|
||||
const float w = wmax.x - wmin.x;
|
||||
const float h = wmax.y - wmin.y;
|
||||
graph_labels_draw_at(g, s.cam_x, s.cam_y, s.zoom,
|
||||
wmin.x, wmin.y, w, h, p, cb, user);
|
||||
}
|
||||
|
||||
} // namespace graph
|
||||
Reference in New Issue
Block a user