From fdf7c82bd78098ea559c301c0335e30e986bd2b0 Mon Sep 17 00:00:00 2001 From: Egutierrez Date: Sat, 25 Apr 2026 21:53:01 +0200 Subject: [PATCH] feat(primitives_gallery): demos para los 5 charts cientificos (issue 0034) Anade 5 entradas a la gallery (treemap, sankey, chord, contour, voronoi) con datos sinteticos coherentes: - treemap: 6 items 'gastos por categoria' - sankey: 8 nodos clientes -> productos -> categorias (DAG) - chord: matriz 6x6 simetrica de flujos entre paises - contour: mezcla de 2 gaussianas 32x32 + 5 niveles - voronoi: 30 seeds aleatorias + colores aleatorios Wire-up additions only (demos.h, main.cpp k_demos[], CMakeLists.txt). --- cpp/apps/primitives_gallery/CMakeLists.txt | 7 + cpp/apps/primitives_gallery/demos.h | 5 + .../primitives_gallery/demos_scientific.cpp | 208 ++++++++++++++++++ cpp/apps/primitives_gallery/main.cpp | 5 + 4 files changed, 225 insertions(+) create mode 100644 cpp/apps/primitives_gallery/demos_scientific.cpp diff --git a/cpp/apps/primitives_gallery/CMakeLists.txt b/cpp/apps/primitives_gallery/CMakeLists.txt index 6812bf9f..725fe2b4 100644 --- a/cpp/apps/primitives_gallery/CMakeLists.txt +++ b/cpp/apps/primitives_gallery/CMakeLists.txt @@ -8,6 +8,7 @@ add_imgui_app(primitives_gallery demos_text_editor.cpp demos_gl_texture.cpp demos_extras.cpp + demos_scientific.cpp # text_editor + file_watcher (issue 0025) ${CMAKE_SOURCE_DIR}/functions/core/text_editor.cpp ${CMAKE_SOURCE_DIR}/functions/core/file_watcher.cpp @@ -39,6 +40,12 @@ add_imgui_app(primitives_gallery ${CMAKE_SOURCE_DIR}/functions/viz/gauge.cpp ${CMAKE_SOURCE_DIR}/functions/viz/heatmap.cpp ${CMAKE_SOURCE_DIR}/functions/viz/table_view.cpp + # Scientific viz (issue 0034) + ${CMAKE_SOURCE_DIR}/functions/viz/treemap.cpp + ${CMAKE_SOURCE_DIR}/functions/viz/sankey.cpp + ${CMAKE_SOURCE_DIR}/functions/viz/chord.cpp + ${CMAKE_SOURCE_DIR}/functions/viz/contour.cpp + ${CMAKE_SOURCE_DIR}/functions/viz/voronoi.cpp # Graph stack (instanced GPU + Barnes-Hut + spatial hash) ${CMAKE_SOURCE_DIR}/functions/viz/graph_types.cpp ${CMAKE_SOURCE_DIR}/functions/viz/graph_renderer.cpp diff --git a/cpp/apps/primitives_gallery/demos.h b/cpp/apps/primitives_gallery/demos.h index b7f22c32..ee24a057 100644 --- a/cpp/apps/primitives_gallery/demos.h +++ b/cpp/apps/primitives_gallery/demos.h @@ -34,6 +34,11 @@ void demo_candlestick(); void demo_gauge(); void demo_heatmap(); void demo_table_view(); +void demo_treemap(); // issue 0034 +void demo_sankey(); // issue 0034 +void demo_chord(); // issue 0034 +void demo_contour(); // issue 0034 +void demo_voronoi(); // issue 0034 // --- Gfx --- void demo_shader_canvas(); diff --git a/cpp/apps/primitives_gallery/demos_scientific.cpp b/cpp/apps/primitives_gallery/demos_scientific.cpp new file mode 100644 index 00000000..632b6c9a --- /dev/null +++ b/cpp/apps/primitives_gallery/demos_scientific.cpp @@ -0,0 +1,208 @@ +// demos_scientific.cpp — demos para los 5 charts cientificos del issue 0034: +// treemap, sankey, chord, contour, voronoi. + +#include "demos.h" +#include "demo.h" + +#include "viz/treemap.h" +#include "viz/sankey.h" +#include "viz/chord.h" +#include "viz/contour.h" +#include "viz/voronoi.h" + +#include +#include +#include +#include + +namespace gallery { + +// --------------------------------------------------------------------------- +// treemap +// --------------------------------------------------------------------------- + +void demo_treemap() { + demo_header("treemap", "v1.0.0", + "Squarified treemap (Bruls et al.) para jerarquias planas con valores. " + "Algoritmo puro separado del render."); + + section("Gastos por categoria"); + { + std::vector items = { + {"vivienda", 950.0f, IM_COL32(180, 120, 200, 255)}, + {"comida", 320.0f, IM_COL32(120, 180, 200, 255)}, + {"transporte", 180.0f, IM_COL32(200, 180, 120, 255)}, + {"ocio", 140.0f, IM_COL32(200, 120, 160, 255)}, + {"salud", 90.0f, IM_COL32(120, 200, 160, 255)}, + {"otros", 60.0f, IM_COL32(160, 160, 200, 255)}, + }; + treemap("##gastos", items, ImVec2(-1, 320)); + } + + code_block( + "std::vector items = {\n" + " {\"vivienda\", 950.0f, IM_COL32(180,120,200,255)},\n" + " {\"comida\", 320.0f, IM_COL32(120,180,200,255)},\n" + " ...\n" + "};\n" + "treemap(\"##gastos\", items, ImVec2(-1, 320));" + ); +} + +// --------------------------------------------------------------------------- +// sankey +// --------------------------------------------------------------------------- + +void demo_sankey() { + demo_header("sankey", "v1.0.0", + "Sankey diagram para flujos source -> target. BFS topologico para columnas, " + "bandas curvas (bezier cubico) para los links. Asume DAG."); + + section("Clientes -> productos -> categorias"); + { + std::vector nodes = { + {"premium"}, {"basicos"}, + {"laptops"}, {"phones"}, {"tablets"}, + {"hardware"}, {"software"}, {"servicios"}, + }; + std::vector links = { + // clientes -> productos + {0, 2, 80}, {0, 3, 30}, {0, 4, 15}, + {1, 3, 60}, {1, 4, 40}, {1, 2, 20}, + // productos -> categorias + {2, 5, 70}, {2, 6, 30}, + {3, 5, 50}, {3, 7, 40}, + {4, 6, 35}, {4, 7, 20}, + }; + sankey("##flow", nodes, links, ImVec2(-1, 360)); + } + + code_block( + "std::vector nodes = {{\"premium\"}, {\"basicos\"}, ...};\n" + "std::vector links = {{0, 2, 80}, {0, 3, 30}, ...};\n" + "sankey(\"##flow\", nodes, links, ImVec2(-1, 360));" + ); +} + +// --------------------------------------------------------------------------- +// chord +// --------------------------------------------------------------------------- + +void demo_chord() { + demo_header("chord", "v1.0.0", + "Chord diagram para matrices NxN. Arcos proporcionales a sum(row) + cuerdas " + "internas con bezier cubico."); + + section("Flujos entre paises (matriz 6x6 simetrica)"); + { + constexpr int N = 6; + // simetrica de "comercio" entre 6 paises + static float M[N * N] = { + 0, 10, 6, 12, 4, 3, + 10, 0, 14, 3, 8, 2, + 6, 14, 0, 9, 11, 5, + 12, 3, 9, 0, 7, 6, + 4, 8, 11, 7, 0, 13, + 3, 2, 5, 6, 13, 0, + }; + static const char* labels[N] = {"ESP", "FRA", "ITA", "DEU", "PRT", "GBR"}; + chord("##chord", M, N, labels, ImVec2(420, 420)); + } + + code_block( + "float M[N*N] = { // simetrica\n" + " 0, 10, 6, 12, 4, 3,\n" + " 10, 0, 14, 3, 8, 2,\n" + " ...\n" + "};\n" + "const char* labels[6] = {\"ESP\",\"FRA\",\"ITA\",\"DEU\",\"PRT\",\"GBR\"};\n" + "chord(\"##c\", M, 6, labels);" + ); +} + +// --------------------------------------------------------------------------- +// contour +// --------------------------------------------------------------------------- + +void demo_contour() { + demo_header("contour", "v1.0.0", + "Contour plot 2D via marching squares. Para una gaussiana centrada los " + "contornos resultantes son aproximadamente concentricos."); + + constexpr int N = 32; + static float grid[N * N]; + static bool init = false; + if (!init) { + // Mezcla de 2 gaussianas (peak central + secundario) + for (int y = 0; y < N; y++) { + for (int x = 0; x < N; x++) { + float dx1 = x - N * 0.45f, dy1 = y - N * 0.5f; + float dx2 = x - N * 0.75f, dy2 = y - N * 0.3f; + float v = std::exp(-(dx1 * dx1 + dy1 * dy1) / 70.0f) + + 0.55f * std::exp(-(dx2 * dx2 + dy2 * dy2) / 30.0f); + grid[y * N + x] = v; + } + } + init = true; + } + static const float levels[] = {0.15f, 0.30f, 0.50f, 0.70f, 0.90f}; + contour("##gauss", grid, N, N, levels, 5, ImVec2(-1, 320)); + + code_block( + "constexpr int N = 32;\n" + "float grid[N*N];\n" + "for (int y = 0; y < N; y++)\n" + " for (int x = 0; x < N; x++) {\n" + " float dx = x - N/2.0f, dy = y - N/2.0f;\n" + " grid[y*N + x] = std::exp(-(dx*dx + dy*dy) / 80.0f);\n" + " }\n" + "float levels[] = {0.15f, 0.30f, 0.50f, 0.70f, 0.90f};\n" + "contour(\"##gauss\", grid, N, N, levels, 5);" + ); +} + +// --------------------------------------------------------------------------- +// voronoi +// --------------------------------------------------------------------------- + +void demo_voronoi() { + demo_header("voronoi", "v1.0.0", + "Diagrama de Voronoi via raster brute-force (MVP). Tiles 4x4 px coloreados " + "por el seed mas cercano. Suficiente para N <= 200."); + + constexpr int N = 30; + static ImVec2 seeds [N]; + static ImU32 colors[N]; + static bool init = false; + if (!init) { + unsigned seed = 7; + auto rnd = [&]() { + seed = seed * 1103515245u + 12345u; + return (float)((seed >> 16) & 0x7fff) / 32768.0f; + }; + // El render escala automaticamente; las posiciones se asumen en coords del rect. + // Como no sabemos W/H aqui, usamos coords aproximadas para 600x300 y el clip + // dentro de voronoi se encarga de mantenerlas en rango. + for (int i = 0; i < N; i++) { + seeds [i] = ImVec2(rnd() * 600.0f, rnd() * 300.0f); + colors[i] = IM_COL32(40 + (int)(rnd() * 200), + 40 + (int)(rnd() * 200), + 60 + (int)(rnd() * 195), + 230); + } + init = true; + } + voronoi("##v", seeds, N, colors, ImVec2(-1, 300)); + + code_block( + "ImVec2 seeds[30];\n" + "ImU32 colors[30];\n" + "for (int i = 0; i < 30; i++) {\n" + " seeds [i] = ImVec2(rnd() * 600.0f, rnd() * 300.0f);\n" + " colors[i] = IM_COL32(rnd_byte(), rnd_byte(), rnd_byte(), 230);\n" + "}\n" + "voronoi(\"##v\", seeds, 30, colors, ImVec2(-1, 300));" + ); +} + +} // namespace gallery diff --git a/cpp/apps/primitives_gallery/main.cpp b/cpp/apps/primitives_gallery/main.cpp index 269bfe6b..e1dcad28 100644 --- a/cpp/apps/primitives_gallery/main.cpp +++ b/cpp/apps/primitives_gallery/main.cpp @@ -61,6 +61,11 @@ static const DemoEntry k_demos[] = { {"gauge", "gauge", "Viz", &gallery::demo_gauge}, {"heatmap", "heatmap", "Viz", &gallery::demo_heatmap}, {"table_view", "table_view", "Viz", &gallery::demo_table_view}, + {"treemap", "treemap", "Viz", &gallery::demo_treemap}, + {"sankey", "sankey", "Viz", &gallery::demo_sankey}, + {"chord", "chord", "Viz", &gallery::demo_chord}, + {"contour", "contour", "Viz", &gallery::demo_contour}, + {"voronoi", "voronoi", "Viz", &gallery::demo_voronoi}, // Gfx (shaders_lab core) {"shader_canvas", "shader_canvas", "Gfx", &gallery::demo_shader_canvas}, {"gl_texture", "gl_texture_load", "Gfx", &gallery::demo_gl_texture}, // wave 1