d0bce11a40
Para cada tile 4x4 px del rect de render: encontrar seed mas cercano (distancia Euclidea) y rellenar con su color. Suficiente para N<=200 seeds en region <=600x400. voronoi_layout deja polygon vacio en MVP — solo rellena seed/color. Para extraer poligonos analiticos seria necesario half-plane intersections (Fortune) — diferido a otro issue.
84 lines
2.5 KiB
C++
84 lines
2.5 KiB
C++
#include "viz/voronoi.h"
|
|
|
|
#include <cmath>
|
|
|
|
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<VoronoiCell> voronoi_layout(const ImVec2* seeds, int n, ImVec2 /*region*/) {
|
|
std::vector<VoronoiCell> 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();
|
|
}
|