#include "viz/voronoi.h" #include namespace { inline int nearest_seed(float px, float py, const ImVec2* seeds, int n) { int best = 0; float bd2 = 1e30f; for (int i = 0; i < n; i++) { float dx = px - seeds[i].x; float dy = py - seeds[i].y; float d2 = dx * dx + dy * dy; if (d2 < bd2) { bd2 = d2; best = i; } } return best; } } // namespace std::vector voronoi_layout(const ImVec2* seeds, int n, ImVec2 /*region*/) { std::vector out; if (!seeds || n <= 0) return out; out.resize(n); for (int i = 0; i < n; i++) { out[i].seed = seeds[i]; out[i].color = IM_COL32(120, 144, 252, 230); out[i].polygon.clear(); } return out; } void voronoi(const char* id, const ImVec2* seeds, int n, const ImU32* colors, ImVec2 size) { ImGui::PushID(id); ImVec2 avail = ImGui::GetContentRegionAvail(); float W = (size.x > 0.0f) ? size.x : avail.x; float H = (size.y > 0.0f) ? size.y : 200.0f; ImVec2 origin = ImGui::GetCursorScreenPos(); ImGui::Dummy(ImVec2(W, H)); if (!seeds || n <= 0) { ImGui::PopID(); return; } ImDrawList* dl = ImGui::GetWindowDrawList(); // Raster: tile de 4x4 pixels. Region <= ~600x400 con N<=200 -> ~150*100 = 15000 calls, // dentro de presupuesto frame. const float tile = 4.0f; int cols = (int)std::ceil(W / tile); int rows = (int)std::ceil(H / tile); for (int ry = 0; ry < rows; ry++) { float py = (ry + 0.5f) * tile; if (py > H) py = H; for (int rx = 0; rx < cols; rx++) { float px = (rx + 0.5f) * tile; if (px > W) px = W; int idx = nearest_seed(px, py, seeds, n); ImU32 col = colors ? colors[idx] : IM_COL32(120, 144, 252, 230); ImVec2 a(origin.x + rx * tile, origin.y + ry * tile); ImVec2 b(origin.x + std::min((rx + 1) * tile, W), origin.y + std::min((ry + 1) * tile, H)); dl->AddRectFilled(a, b, col); } } // Borde y seeds dl->AddRect(origin, ImVec2(origin.x + W, origin.y + H), IM_COL32(80, 80, 90, 220), 0.0f, 0, 1.0f); for (int i = 0; i < n; i++) { ImVec2 c(origin.x + seeds[i].x, origin.y + seeds[i].y); dl->AddCircleFilled(c, 2.5f, IM_COL32(20, 22, 28, 255)); dl->AddCircleFilled(c, 1.5f, IM_COL32(245, 246, 250, 255)); } ImGui::PopID(); }