1861205504
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.
84 lines
2.9 KiB
C++
84 lines
2.9 KiB
C++
// 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
|