From cfa39f850bbcd69a3e81fd5d9381c8f95ee2a991 Mon Sep 17 00:00:00 2001 From: chatlanin Date: Fri, 20 Mar 2026 14:44:16 +0300 Subject: [PATCH] add intefaces plugins --- plugin.hpp | 187 ++++++++++++++++++ plugin.t.hpp | 187 ++++++++++++++++++ src/meson.build | 13 ++ .../components/base_plugins/base_plugins.hpp | 12 +- .../gui/components/base_plugins/cpp/base.cpp | 11 ++ .../components/base_plugins/cpp/render.cpp | 2 + .../gui/components/fft_scaled/cpp/base.cpp | 30 +++ .../components/fft_scaled/cpp/on_event.cpp | 8 + .../gui/components/fft_scaled/cpp/render.cpp | 32 +++ .../gui/components/fft_scaled/fft_scaled.hpp | 28 +++ src/monitor/gui/components/graph/cpp/base.cpp | 4 +- .../gui/components/graph/cpp/render.cpp | 10 +- .../gui/components/snapshot/cpp/base.cpp | 2 - src/monitor/gui/components/tabs/cpp/base.cpp | 3 +- src/monitor/utils/plugin.hpp | 128 ++++++------ src/monitor/utils/plugins/fft.hpp | 119 +++++++++++ src/monitor/utils/plugins/magnitude.hpp | 17 ++ src/monitor/utils/plugins/raw_data.hpp | 17 ++ 18 files changed, 723 insertions(+), 87 deletions(-) create mode 100644 plugin.hpp create mode 100644 plugin.t.hpp create mode 100755 src/monitor/gui/components/fft_scaled/cpp/base.cpp create mode 100755 src/monitor/gui/components/fft_scaled/cpp/on_event.cpp create mode 100755 src/monitor/gui/components/fft_scaled/cpp/render.cpp create mode 100755 src/monitor/gui/components/fft_scaled/fft_scaled.hpp create mode 100644 src/monitor/utils/plugins/fft.hpp create mode 100644 src/monitor/utils/plugins/magnitude.hpp create mode 100644 src/monitor/utils/plugins/raw_data.hpp diff --git a/plugin.hpp b/plugin.hpp new file mode 100644 index 0000000..90bd686 --- /dev/null +++ b/plugin.hpp @@ -0,0 +1,187 @@ +#pragma once + +#include "monitor/utils/plugins/plugin.hpp" + +namespace monitor::utils +{ + struct raw_plugin : public plugin + { + public: + enum class TYPE + { + RAW_DATA, + MAGNITUDE, + ENERGY + }; + + public: + hr::result m_result; + TYPE m_type; + std::string m_display_name; + + public: + struct graph + { + public: + // градуировка осьи X + hr::fvec_t m_ox; + // максимальное значение по оси Y + double m_max_element = 0.0; + // размер данных дял отрисовки + std::size_t m_size = 0; + // кол-во линий графика + std::size_t m_line_count = 0; + // тут кол-во графиков на массив данных из этих графиков т.е.: + // [1] = [1, 2, ..., 1'000'000'000] + // [2] = [1, 2, ..., 1'000'000'000] + std::vector m_data; + // говорит нужно ли делать сжатие графика ли нет + bool m_is_scale = false; + + void fill_ox(std::size_t start_pos = 0) + { + m_ox.clear(); + for (std::size_t i = start_pos; i < start_pos + m_size; ++i) m_ox.push_back(i); + } + + void init() + { + m_data.reserve(m_line_count); + m_ox.reserve(m_size); + for (std::size_t i = 0; i < m_line_count; ++i) m_data.push_back(hr::fvec_t(m_size, 0.f)); + } + + } m_graph; + + public: + bool empty() { return m_result.empty(); } + + void graph_init() + { + try + { + auto raw_size = m_result.size(); + if (raw_size == 0) throw std::invalid_argument("Error set data in plugin: empty data"); + + m_graph.m_is_scale = raw_size > var::MAX_RENDER_SIZE; + m_graph.m_size = std::min(raw_size, var::MAX_RENDER_SIZE); + m_graph.m_line_count = m_result.m_data.size(); + m_graph.init(); + m_graph.fill_ox(); + } + catch(std::exception& e) + { + hack::error()(e.what()); + } + } + + // этот метод запускается один раз при первом рендеринге + // для заполнения начальными данными + void fill() + { + if (m_graph.m_is_scale) + { + m_step = m_result.size() / m_graph.m_size + 1; + + std::size_t line_count = 0; + for (auto& gd : m_graph.m_data) + { + std::size_t index = 0; + for (auto& g : gd) + { + float tmp_e = 0.f; + for (std::size_t j = index - m_step; j < index; ++j) + { + auto e = m_result.m_data[line_count][j].m_value; + tmp_e = hack::math::max_abs(e, tmp_e); + } + g = tmp_e; + m_graph.m_max_element = std::fabs(hack::math::max_abs(g, m_graph.m_max_element)); + + index += m_step; + if (index > m_result.size()) index = m_result.size(); + } + ++line_count; + } + } + else + { + // заполняется, когда данных пришло меньше чем нужно для полного рендеринга + std::size_t graph_count = 0; + for (auto el : m_result.m_data) + { + std::size_t index = 0; + for (auto e : el) + { + m_graph.m_max_element = hack::math::max(e.m_value, m_graph.m_max_element); + m_graph.m_data[graph_count][index] = e.m_value; + ++index; + } + ++graph_count; + } + } + } + + std::size_t m_local_k2 = 0; + std::size_t m_step; + + bool is_scale() + { + return m_graph.m_is_scale; + } + + // Это основной меод вычисления данных, которые нужно отрисовать + // 1. Проверяем размер сырых данных + // - если их больше чем var::MAX_RENDER_SIZE, то делаем сжатие + // - если их меньше, то отрисовка идет полностью и fill_ox уже заполнен так как надо и при масштабировании ни чего не пересчитывается is_scale + void fill(ImPlotRect current_limits) + { + // кол-во данных, которые мы сейчас хотим отрисовать, когда поменяли масштаб + auto total_dots_for_render = current_limits.Size().x; + // тоже, что начальный m_step, но если m_step меняется, то этот постоянный + // т.е. это максимальный коефиниент сужения графика + std::size_t k1 = m_result.size() / m_graph.m_size + 1; + // на сколько изменилось кол-во точек, которые нужно отрисовать + std::size_t k2 = var::MAX_RENDER_SIZE / total_dots_for_render - 1.f; + + // стэк условий, котолрые ограничивают лишние расчеты и сохраняют текущие данные + if (k1 <= k2 && k2 != 0) return; + if (m_local_k2 == k2 && k2 != 0) return; + m_local_k2 = k2; + + // сколько сместилось точке отрисовки во время масштабирования за экран (влево) + std::size_t skip_dots = current_limits.Min().x; + // кол-во точек, которые нужно пропустить из сырых данных чтобы они не были отрисованы во время масштабирования + std::size_t pos = skip_dots * (m_step + k2); + // шаг пропуска, по которому делаем сужение графика + m_step = k1 - k2; + + std::size_t line_count = 0; + for (auto& gd : m_graph.m_data) + { + std::size_t index = pos; + for (auto& g : gd) + { + float tmp_e = 0.f; + for (std::size_t j = index - m_step; j < index; ++j) + { + auto e = m_result.m_data[line_count][j].m_value; + // основной критерий сужения: берем максимальный элемент из данного интервала m_step + tmp_e = hack::math::max_abs(e, tmp_e); + } + g = tmp_e; + m_graph.m_max_element = std::fabs(hack::math::max_abs(g, m_graph.m_max_element)); + + index += m_step; + if (index > m_result.size()) index = m_result.size(); + } + ++line_count; + } + + // нужно передать смещение для установки градации + m_graph.fill_ox(skip_dots); + } + }; +} + + diff --git a/plugin.t.hpp b/plugin.t.hpp new file mode 100644 index 0000000..90bd686 --- /dev/null +++ b/plugin.t.hpp @@ -0,0 +1,187 @@ +#pragma once + +#include "monitor/utils/plugins/plugin.hpp" + +namespace monitor::utils +{ + struct raw_plugin : public plugin + { + public: + enum class TYPE + { + RAW_DATA, + MAGNITUDE, + ENERGY + }; + + public: + hr::result m_result; + TYPE m_type; + std::string m_display_name; + + public: + struct graph + { + public: + // градуировка осьи X + hr::fvec_t m_ox; + // максимальное значение по оси Y + double m_max_element = 0.0; + // размер данных дял отрисовки + std::size_t m_size = 0; + // кол-во линий графика + std::size_t m_line_count = 0; + // тут кол-во графиков на массив данных из этих графиков т.е.: + // [1] = [1, 2, ..., 1'000'000'000] + // [2] = [1, 2, ..., 1'000'000'000] + std::vector m_data; + // говорит нужно ли делать сжатие графика ли нет + bool m_is_scale = false; + + void fill_ox(std::size_t start_pos = 0) + { + m_ox.clear(); + for (std::size_t i = start_pos; i < start_pos + m_size; ++i) m_ox.push_back(i); + } + + void init() + { + m_data.reserve(m_line_count); + m_ox.reserve(m_size); + for (std::size_t i = 0; i < m_line_count; ++i) m_data.push_back(hr::fvec_t(m_size, 0.f)); + } + + } m_graph; + + public: + bool empty() { return m_result.empty(); } + + void graph_init() + { + try + { + auto raw_size = m_result.size(); + if (raw_size == 0) throw std::invalid_argument("Error set data in plugin: empty data"); + + m_graph.m_is_scale = raw_size > var::MAX_RENDER_SIZE; + m_graph.m_size = std::min(raw_size, var::MAX_RENDER_SIZE); + m_graph.m_line_count = m_result.m_data.size(); + m_graph.init(); + m_graph.fill_ox(); + } + catch(std::exception& e) + { + hack::error()(e.what()); + } + } + + // этот метод запускается один раз при первом рендеринге + // для заполнения начальными данными + void fill() + { + if (m_graph.m_is_scale) + { + m_step = m_result.size() / m_graph.m_size + 1; + + std::size_t line_count = 0; + for (auto& gd : m_graph.m_data) + { + std::size_t index = 0; + for (auto& g : gd) + { + float tmp_e = 0.f; + for (std::size_t j = index - m_step; j < index; ++j) + { + auto e = m_result.m_data[line_count][j].m_value; + tmp_e = hack::math::max_abs(e, tmp_e); + } + g = tmp_e; + m_graph.m_max_element = std::fabs(hack::math::max_abs(g, m_graph.m_max_element)); + + index += m_step; + if (index > m_result.size()) index = m_result.size(); + } + ++line_count; + } + } + else + { + // заполняется, когда данных пришло меньше чем нужно для полного рендеринга + std::size_t graph_count = 0; + for (auto el : m_result.m_data) + { + std::size_t index = 0; + for (auto e : el) + { + m_graph.m_max_element = hack::math::max(e.m_value, m_graph.m_max_element); + m_graph.m_data[graph_count][index] = e.m_value; + ++index; + } + ++graph_count; + } + } + } + + std::size_t m_local_k2 = 0; + std::size_t m_step; + + bool is_scale() + { + return m_graph.m_is_scale; + } + + // Это основной меод вычисления данных, которые нужно отрисовать + // 1. Проверяем размер сырых данных + // - если их больше чем var::MAX_RENDER_SIZE, то делаем сжатие + // - если их меньше, то отрисовка идет полностью и fill_ox уже заполнен так как надо и при масштабировании ни чего не пересчитывается is_scale + void fill(ImPlotRect current_limits) + { + // кол-во данных, которые мы сейчас хотим отрисовать, когда поменяли масштаб + auto total_dots_for_render = current_limits.Size().x; + // тоже, что начальный m_step, но если m_step меняется, то этот постоянный + // т.е. это максимальный коефиниент сужения графика + std::size_t k1 = m_result.size() / m_graph.m_size + 1; + // на сколько изменилось кол-во точек, которые нужно отрисовать + std::size_t k2 = var::MAX_RENDER_SIZE / total_dots_for_render - 1.f; + + // стэк условий, котолрые ограничивают лишние расчеты и сохраняют текущие данные + if (k1 <= k2 && k2 != 0) return; + if (m_local_k2 == k2 && k2 != 0) return; + m_local_k2 = k2; + + // сколько сместилось точке отрисовки во время масштабирования за экран (влево) + std::size_t skip_dots = current_limits.Min().x; + // кол-во точек, которые нужно пропустить из сырых данных чтобы они не были отрисованы во время масштабирования + std::size_t pos = skip_dots * (m_step + k2); + // шаг пропуска, по которому делаем сужение графика + m_step = k1 - k2; + + std::size_t line_count = 0; + for (auto& gd : m_graph.m_data) + { + std::size_t index = pos; + for (auto& g : gd) + { + float tmp_e = 0.f; + for (std::size_t j = index - m_step; j < index; ++j) + { + auto e = m_result.m_data[line_count][j].m_value; + // основной критерий сужения: берем максимальный элемент из данного интервала m_step + tmp_e = hack::math::max_abs(e, tmp_e); + } + g = tmp_e; + m_graph.m_max_element = std::fabs(hack::math::max_abs(g, m_graph.m_max_element)); + + index += m_step; + if (index > m_result.size()) index = m_result.size(); + } + ++line_count; + } + + // нужно передать смещение для установки градации + m_graph.fill_ox(skip_dots); + } + }; +} + + diff --git a/src/meson.build b/src/meson.build index afe95bc..4cfcb5c 100755 --- a/src/meson.build +++ b/src/meson.build @@ -15,9 +15,17 @@ headers = [ 'monitor/gui/components/base_plugins/base_plugins.hpp', 'monitor/gui/components/base_controls/base_controls.hpp', 'monitor/gui/components/graph/graph.hpp', + 'monitor/gui/components/fft_scaled/fft_scaled.hpp', ############ UTILS 'monitor/utils/var.hpp', + 'monitor/utils/func.hpp', + 'monitor/utils/plugin.hpp', + 'monitor/utils/plugins/raw_data.hpp', + 'monitor/utils/plugins/magnitude.hpp', + 'monitor/utils/plugins/fft.hpp', + + ############ LIBS 'monitor/libs/audio/audio.hpp', 'monitor/libs/gtkfd/gtkfd.hpp', @@ -78,6 +86,11 @@ sources = [ 'monitor/gui/components/graph/cpp/on_event.cpp', 'monitor/gui/components/graph/cpp/render.cpp', + # win/tabs/snapshot/base_plugins/fft_scaled + 'monitor/gui/components/fft_scaled/cpp/base.cpp', + 'monitor/gui/components/fft_scaled/cpp/on_event.cpp', + 'monitor/gui/components/fft_scaled/cpp/render.cpp', + # win/tabs/snapshot/base_controls 'monitor/gui/components/base_controls/cpp/base.cpp', 'monitor/gui/components/base_controls/cpp/on_event.cpp', diff --git a/src/monitor/gui/components/base_plugins/base_plugins.hpp b/src/monitor/gui/components/base_plugins/base_plugins.hpp index 39d1e8f..282e02f 100644 --- a/src/monitor/gui/components/base_plugins/base_plugins.hpp +++ b/src/monitor/gui/components/base_plugins/base_plugins.hpp @@ -2,6 +2,7 @@ #include #include "monitor/gui/components/graph/graph.hpp" +#include "monitor/gui/components/fft_scaled/fft_scaled.hpp" namespace monitor::components { @@ -16,16 +17,15 @@ namespace monitor::components ImVec2 m_pos = { 4.f, 70.f }; ImGuiTabBarFlags m_tab_bar_flags { ImGuiTabBarFlags_None }; std::size_t m_current_open_index = 0; - graph m_graph; std::string m_snapshot_id; + private: + graph m_graph; + // fft_scaled m_fft_scaled; + private: hr::setup m_setup; - std::vector> m_base_plugins = { - std::make_shared(utils::plugin{ .m_type = utils::plugin::TYPE::RAW_DATA, .m_display_name = "Raw Data"}), - std::make_shared(utils::plugin{ .m_type = utils::plugin::TYPE::MAGNITUDE, .m_display_name = "Magnitude"}), - std::make_shared(utils::plugin{ .m_type = utils::plugin::TYPE::ENERGY, .m_display_name = "Energy"}), - }; + std::vector> m_base_plugins; public: void init(std::string snapshot_id, hr::setup setup); diff --git a/src/monitor/gui/components/base_plugins/cpp/base.cpp b/src/monitor/gui/components/base_plugins/cpp/base.cpp index fa7567c..b891c6d 100644 --- a/src/monitor/gui/components/base_plugins/cpp/base.cpp +++ b/src/monitor/gui/components/base_plugins/cpp/base.cpp @@ -1,4 +1,6 @@ #include "monitor/gui/components/base_plugins/base_plugins.hpp" +#include "monitor/utils/plugins/raw_data.hpp" +#include "monitor/utils/plugins/magnitude.hpp" namespace monitor::components { @@ -7,6 +9,11 @@ namespace monitor::components CONNECT(this); m_graph.on_attach(); + // m_fft_scaled.on_attach(); + + m_base_plugins.push_back(std::make_shared(utils::plugins::raw_data{})); + m_base_plugins.push_back(std::make_shared(utils::plugins::magnitude{})); + m_size.x = VE::application::get()->get_glfw()->width() - VE::application::get()->get_glfw()->width() / 4.f; m_size.y = VE::application::get()->get_glfw()->height() / 2.f; } @@ -15,11 +22,13 @@ namespace monitor::components { DISCONNECT(); m_graph.on_detach(); + // m_fft_scaled.on_detach(); } void base_plugins::update() { m_graph.update(); + // m_fft_scaled.update(); } void base_plugins::init(std::string snapshot_id, hr::setup setup) @@ -28,5 +37,7 @@ namespace monitor::components m_setup = setup; m_graph.init(m_snapshot_id, m_setup); m_graph.set_plugin(m_base_plugins[0]); + + // m_fft_scaled.init(m_snapshot_id, m_setup); } } diff --git a/src/monitor/gui/components/base_plugins/cpp/render.cpp b/src/monitor/gui/components/base_plugins/cpp/render.cpp index dbeda58..f9078dc 100644 --- a/src/monitor/gui/components/base_plugins/cpp/render.cpp +++ b/src/monitor/gui/components/base_plugins/cpp/render.cpp @@ -31,6 +31,8 @@ namespace monitor::components ImGui::EndTabBar(); } + // m_fft_scaled.render(); + utils::func::draw_border(m_size); ImGui::EndChild(); diff --git a/src/monitor/gui/components/fft_scaled/cpp/base.cpp b/src/monitor/gui/components/fft_scaled/cpp/base.cpp new file mode 100755 index 0000000..753588e --- /dev/null +++ b/src/monitor/gui/components/fft_scaled/cpp/base.cpp @@ -0,0 +1,30 @@ +#include "monitor/gui/components/fft_scaled/fft_scaled.hpp" + +namespace monitor::components +{ + void fft_scaled::on_attach() + { + CONNECT(this); + } + + void fft_scaled::on_detach() + { + DISCONNECT(); + } + + void fft_scaled::update() + { + } + + void fft_scaled::init(std::string snapshot_id, hr::setup setup) + { + m_snapshot_id = snapshot_id; + m_setup = setup; + m_setup.m_domain = hr::DOMAIN_PLUGIN::FREQUENSY; + m_plugin.m_result = hr::run(m_setup); + m_plugin.init(); + m_plugin.fill(); + } +} + + diff --git a/src/monitor/gui/components/fft_scaled/cpp/on_event.cpp b/src/monitor/gui/components/fft_scaled/cpp/on_event.cpp new file mode 100755 index 0000000..ebfa0aa --- /dev/null +++ b/src/monitor/gui/components/fft_scaled/cpp/on_event.cpp @@ -0,0 +1,8 @@ +#include "monitor/gui/components/fft_scaled/fft_scaled.hpp" + +namespace monitor::components +{ + void fft_scaled::on_event(VE::event& e) + { + } +} diff --git a/src/monitor/gui/components/fft_scaled/cpp/render.cpp b/src/monitor/gui/components/fft_scaled/cpp/render.cpp new file mode 100755 index 0000000..0201d04 --- /dev/null +++ b/src/monitor/gui/components/fft_scaled/cpp/render.cpp @@ -0,0 +1,32 @@ +#include "monitor/gui/components/fft_scaled/fft_scaled.hpp" + +namespace monitor::components +{ + void fft_scaled::render() + { + if (ImPlot::BeginPlot(VE_NO_NAME(m_plugin.m_display_name + m_snapshot_id), ImVec2(-1, 0), ImPlotFlags_NoMenus)) + { + // по оси X + ImPlot::SetupAxes(nullptr, nullptr, ImPlotAxisFlags_Opposite | // смена полюсов у надписей оси x. они вверху + ImPlotAxisFlags_NoSideSwitch | // нельзя перетаскивать оси по сторонам + (m_is_first_render ? ImPlotAxisFlags_AutoFit : ImPlotAxisFlags_None) | // авто подстройка размера по горизонтале + ImPlotAxisFlags_NoHighlight, // не разобрался что это там подсвечивается, что-то с фоном оси + // по оси Y + ImPlotAxisFlags_AutoFit | // авто подстройка размера по вертикале + ImPlotAxisFlags_NoSideSwitch | + ImPlotAxisFlags_NoHighlight | + ImPlotAxisFlags_NoTickLabels // текстовые надписи отображаться не будут + ); + + // ImPlot::SetupAxisLimits(ImAxis_X1, 0.f, m_plugin.m_graph.m_size); + // ImPlot::SetupAxisLimits(ImAxis_Y1, 0.f, m_plugin.m_graph.m_max_element + 2.f); + // ImPlot::SetupAxisLimitsConstraints(ImAxis_X1, 0, INFINITY); + // ImPlot::SetupLegend(ImPlotLocation_NorthEast); + // + // ImPlot::PlotStems(VE_NAME("fft_scaled" + m_snapshot_id), m_plugin.m_graph.m_ox.data(), m_plugin.m_graph.m_data[0].data(), m_plugin.m_graph.m_data[0].size()); + + m_is_first_render = false; + ImPlot::EndPlot(); + } + } +} diff --git a/src/monitor/gui/components/fft_scaled/fft_scaled.hpp b/src/monitor/gui/components/fft_scaled/fft_scaled.hpp new file mode 100755 index 0000000..1a07dfc --- /dev/null +++ b/src/monitor/gui/components/fft_scaled/fft_scaled.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include +#include +#include "monitor/utils/plugins/fft.hpp" + +namespace monitor::components +{ + class fft_scaled : public VE::layer, public VE::flags, public VE::connector + { + VE_OVERIDE(); + VE_EVENT_OVERIDE(); + + private: + ImVec2 m_size = { 0.f, 0.f }; + ImGuiTabBarFlags m_tab_bar_flags { ImGuiTabBarFlags_None }; + ImPlotRect m_current_limits; + bool m_is_first_render = true; + + public: + void init(std::string snapshot_id, hr::setup setup); + + private: + utils::plugins::fft m_plugin; + hr::setup m_setup; + std::string m_snapshot_id; + }; +} diff --git a/src/monitor/gui/components/graph/cpp/base.cpp b/src/monitor/gui/components/graph/cpp/base.cpp index a33775c..ff0d277 100755 --- a/src/monitor/gui/components/graph/cpp/base.cpp +++ b/src/monitor/gui/components/graph/cpp/base.cpp @@ -46,7 +46,7 @@ namespace monitor::components } if (!m_plugin->empty()) { - m_plugin->graph_init(); + m_plugin->init(); m_plugin->fill(); } else @@ -62,7 +62,7 @@ namespace monitor::components if (m_current_limits.Min().x != current_limits.Min().x) { m_current_limits = current_limits; - m_plugin->fill(m_current_limits); + m_plugin->refresh(m_current_limits); } } } diff --git a/src/monitor/gui/components/graph/cpp/render.cpp b/src/monitor/gui/components/graph/cpp/render.cpp index b6899a3..1cee6e8 100755 --- a/src/monitor/gui/components/graph/cpp/render.cpp +++ b/src/monitor/gui/components/graph/cpp/render.cpp @@ -18,19 +18,19 @@ namespace monitor::components ImPlotAxisFlags_NoTickLabels // текстовые надписи отображаться не будут ); - ImPlot::SetupAxisLimits(ImAxis_X1, 0.f, m_plugin->m_graph.m_size); - ImPlot::SetupAxisLimits(ImAxis_Y1, 0.f, m_plugin->m_graph.m_max_element + 2.f); + ImPlot::SetupAxisLimits(ImAxis_X1, 0.f, m_plugin->m_size); + ImPlot::SetupAxisLimits(ImAxis_Y1, 0.f, m_plugin->m_result.m_max + 2.f); ImPlot::SetupAxisLimitsConstraints(ImAxis_X1, 0, INFINITY); ImPlot::SetupLegend(ImPlotLocation_NorthEast); refresh(ImPlot::GetPlotLimits()); - for (std::size_t i = 0; i < m_plugin->m_graph.m_line_count; ++i) + for (std::size_t i = 0; i < m_plugin->m_line_count; ++i) { if (m_plugin->m_type == utils::plugin::TYPE::ENERGY) - ImPlot::PlotStems(VE_NAME(std::to_string(i)), m_plugin->m_graph.m_ox.data(), m_plugin->m_graph.m_data[i].data(), m_plugin->m_graph.m_data[i].size()); + ImPlot::PlotStems(VE_NAME(std::to_string(i)), m_plugin->m_ox.data(), m_plugin->m_line_data[i].data(), m_plugin->m_line_data[i].size()); else - ImPlot::PlotLine(VE_NAME(std::to_string(i)), m_plugin->m_graph.m_ox.data(), m_plugin->m_graph.m_data[i].data(), m_plugin->m_graph.m_data[i].size()); + ImPlot::PlotLine(VE_NAME(std::to_string(i)), m_plugin->m_ox.data(), m_plugin->m_line_data[i].data(), m_plugin->m_line_data[i].size()); } m_is_first_render = false; diff --git a/src/monitor/gui/components/snapshot/cpp/base.cpp b/src/monitor/gui/components/snapshot/cpp/base.cpp index f6c36f6..fd40fce 100755 --- a/src/monitor/gui/components/snapshot/cpp/base.cpp +++ b/src/monitor/gui/components/snapshot/cpp/base.cpp @@ -10,8 +10,6 @@ namespace monitor::components m_base_controls.on_attach(); - - // HERE // то что ниже будем убирать m_audio.on_attach(); diff --git a/src/monitor/gui/components/tabs/cpp/base.cpp b/src/monitor/gui/components/tabs/cpp/base.cpp index 577b16b..174ac0b 100755 --- a/src/monitor/gui/components/tabs/cpp/base.cpp +++ b/src/monitor/gui/components/tabs/cpp/base.cpp @@ -6,7 +6,6 @@ namespace monitor::components void tabs::on_attach() { CONNECT(this); - for (auto & s : m_snapshots) s->on_attach(); } void tabs::on_detach() @@ -26,8 +25,8 @@ namespace monitor::components void tabs::create_snapshot(hr::setup setup) { auto s = std::make_shared(); - s->init(setup); s->on_attach(); + s->init(setup); m_snapshots.push_back(s); VE::event e { utils::event_type::CREATE_SNAPSHOT_COMPLETED, nullptr }; diff --git a/src/monitor/utils/plugin.hpp b/src/monitor/utils/plugin.hpp index 74e57c3..ea4af17 100644 --- a/src/monitor/utils/plugin.hpp +++ b/src/monitor/utils/plugin.hpp @@ -8,10 +8,15 @@ namespace monitor::utils { struct plugin { + public: + plugin() = default; + virtual ~plugin() = default; + public: enum class TYPE { RAW_DATA, + FFT, MAGNITUDE, ENERGY }; @@ -19,57 +24,42 @@ namespace monitor::utils public: hr::result m_result; TYPE m_type; + + public: + // градуировка осьи X + hr::fvec_t m_ox; + // размер данных для отрисовки + std::size_t m_size = 0; + // кол-во линий графика + std::size_t m_line_count = 0; + // тут кол-во графиков на массив данных из этих графиков т.е.: + // [1] = [1, 2, ..., 1'000'000'000] + // [2] = [1, 2, ..., 1'000'000'000] + std::vector m_line_data; + // говорит нужно ли делать сжатие графика ли нет + bool m_is_scale = false; std::string m_display_name; + std::size_t m_step = 0; + // это кол-во точек, которые нужно отрисовать с учетом текущего масштаба но в прошлом шаге + std::size_t m_past_k2 = 0; public: - struct graph - { - public: - // градуировка осьи X - hr::fvec_t m_ox; - // максимальное значение по оси Y - double m_max_element = 0.0; - // размер данных дял отрисовки - std::size_t m_size = 0; - // кол-во линий графика - std::size_t m_line_count = 0; - // тут кол-во графиков на массив данных из этих графиков т.е.: - // [1] = [1, 2, ..., 1'000'000'000] - // [2] = [1, 2, ..., 1'000'000'000] - std::vector m_data; - // говорит нужно ли делать сжатие графика ли нет - bool m_is_scale = false; + virtual bool empty() { return m_result.empty(); } - void fill_ox(std::size_t start_pos = 0) - { - m_ox.clear(); - for (std::size_t i = start_pos; i < start_pos + m_size; ++i) m_ox.push_back(i); - } - - void init() - { - m_data.reserve(m_line_count); - m_ox.reserve(m_size); - for (std::size_t i = 0; i < m_line_count; ++i) m_data.push_back(hr::fvec_t(m_size, 0.f)); - } - - } m_graph; - - public: - bool empty() { return m_result.empty(); } - - void graph_init() + virtual void init() { try { - auto raw_size = m_result.size(); + auto raw_size = m_result.m_size; if (raw_size == 0) throw std::invalid_argument("Error set data in plugin: empty data"); - m_graph.m_is_scale = raw_size > var::MAX_RENDER_SIZE; - m_graph.m_size = std::min(raw_size, var::MAX_RENDER_SIZE); - m_graph.m_line_count = m_result.m_data.size(); - m_graph.init(); - m_graph.fill_ox(); + m_is_scale = raw_size > var::MAX_RENDER_SIZE; + m_size = std::min(raw_size, var::MAX_RENDER_SIZE); + m_line_count = m_result.m_data.size(); + m_line_data.reserve(m_line_count); + m_ox.reserve(m_size); + for (std::size_t i = 0; i < m_line_count; ++i) m_line_data.push_back(hr::fvec_t(m_size, 0.f)); + fill_ox(); } catch(std::exception& e) { @@ -77,16 +67,22 @@ namespace monitor::utils } } + virtual void fill_ox(std::size_t start_pos = 0) + { + m_ox.clear(); + for (std::size_t i = start_pos; i < m_size + start_pos; ++i) m_ox.push_back(i); + } + // этот метод запускается один раз при первом рендеринге // для заполнения начальными данными - void fill() + virtual void fill() { - if (m_graph.m_is_scale) + if (m_is_scale) { - m_step = m_result.size() / m_graph.m_size + 1; + m_step = m_result.m_size / m_size + 1; std::size_t line_count = 0; - for (auto& gd : m_graph.m_data) + for (auto& gd : m_line_data) { std::size_t index = 0; for (auto& g : gd) @@ -98,10 +94,8 @@ namespace monitor::utils tmp_e = hack::math::max_abs(e, tmp_e); } g = tmp_e; - m_graph.m_max_element = std::fabs(hack::math::max_abs(g, m_graph.m_max_element)); - index += m_step; - if (index > m_result.size()) index = m_result.size(); + if (index > m_result.m_size) index = m_result.m_size; } ++line_count; } @@ -109,47 +103,43 @@ namespace monitor::utils else { // заполняется, когда данных пришло меньше чем нужно для полного рендеринга - std::size_t graph_count = 0; + std::size_t line_count = 0; for (auto el : m_result.m_data) { std::size_t index = 0; for (auto e : el) { - m_graph.m_max_element = hack::math::max(e.m_value, m_graph.m_max_element); - m_graph.m_data[graph_count][index] = e.m_value; + m_line_data[line_count][index] = e.m_value; ++index; } - ++graph_count; + ++line_count; } } } - std::size_t m_local_k2 = 0; - std::size_t m_step; - - bool is_scale() + virtual bool is_scale() { - return m_graph.m_is_scale; + return m_is_scale; } - // Это основной меод вычисления данных, которые нужно отрисовать + // Это метод вычисления данных, которые нужно отрисовать, приизменении масштаба // 1. Проверяем размер сырых данных // - если их больше чем var::MAX_RENDER_SIZE, то делаем сжатие // - если их меньше, то отрисовка идет полностью и fill_ox уже заполнен так как надо и при масштабировании ни чего не пересчитывается is_scale - void fill(ImPlotRect current_limits) + virtual void refresh(ImPlotRect current_limits) { // кол-во данных, которые мы сейчас хотим отрисовать, когда поменяли масштаб auto total_dots_for_render = current_limits.Size().x; // тоже, что начальный m_step, но если m_step меняется, то этот постоянный - // т.е. это максимальный коефиниент сужения графика - std::size_t k1 = m_result.size() / m_graph.m_size + 1; + // т.е. это максимальный коефициент сужения графика + std::size_t k1 = m_result.m_size / m_size + 1; // на сколько изменилось кол-во точек, которые нужно отрисовать std::size_t k2 = var::MAX_RENDER_SIZE / total_dots_for_render - 1.f; - // стэк условий, котолрые ограничивают лишние расчеты и сохраняют текущие данные + // стэк условий, которые ограничивают лишние расчеты и сохраняют текущие данные if (k1 <= k2 && k2 != 0) return; - if (m_local_k2 == k2 && k2 != 0) return; - m_local_k2 = k2; + if (m_past_k2 == k2 && k2 != 0) return; + m_past_k2 = k2; // сколько сместилось точке отрисовки во время масштабирования за экран (влево) std::size_t skip_dots = current_limits.Min().x; @@ -159,7 +149,7 @@ namespace monitor::utils m_step = k1 - k2; std::size_t line_count = 0; - for (auto& gd : m_graph.m_data) + for (auto& gd : m_line_data) { std::size_t index = pos; for (auto& g : gd) @@ -172,16 +162,14 @@ namespace monitor::utils tmp_e = hack::math::max_abs(e, tmp_e); } g = tmp_e; - m_graph.m_max_element = std::fabs(hack::math::max_abs(g, m_graph.m_max_element)); - index += m_step; - if (index > m_result.size()) index = m_result.size(); + if (index > m_result.m_size) index = m_result.m_size; } ++line_count; } // нужно передать смещение для установки градации - m_graph.fill_ox(skip_dots); + fill_ox(skip_dots); } }; } diff --git a/src/monitor/utils/plugins/fft.hpp b/src/monitor/utils/plugins/fft.hpp new file mode 100644 index 0000000..f9bdc1d --- /dev/null +++ b/src/monitor/utils/plugins/fft.hpp @@ -0,0 +1,119 @@ +#pragma once + +#include "monitor/utils/plugin.hpp" + +namespace monitor::utils::plugins +{ + struct fft : public plugin + { + fft() + { + m_type = plugin::TYPE::FFT; + m_display_name = "FFT"; + } + + virtual void init() + { + try + { + // тут просто берем из первой линии, первые данные, т.к это fft см. реализацию самого плагина в harmonica + auto raw_size = m_result.m_data[0][0].m_values.size(); + if (raw_size == 0) throw std::invalid_argument("Error set data in plugin: empty data"); + + m_is_scale = raw_size > var::MAX_RENDER_SIZE; + m_size = std::min(raw_size, var::MAX_RENDER_SIZE); + m_line_count = m_result.m_data.size(); + m_line_data.reserve(m_line_count); + m_ox.reserve(m_result.m_grad.size()); + for (std::size_t i = 0; i < m_line_count; ++i) m_line_data.push_back(hr::fvec_t(m_size, 0.f)); + fill_ox(); + } + catch(std::exception& e) + { + hack::error()(e.what()); + } + } + + virtual void fill_ox(std::size_t start_pos = 0) + { + for (auto x : m_result.m_grad) m_ox.push_back(x); + } + + // этот метод запускается один раз при первом рендеринге + // для заполнения начальными данными + virtual void fill() + { + if (m_is_scale) hack::error()("ДАнных больше чем можем отрисовать на экране, см. что-то с масштабированием..."); + + std::size_t line_count = 0; + for (auto el : m_result.m_data) + { + std::size_t index = 0; + for (auto e : el) + { + m_line_data[line_count][index] = e.m_value; + ++index; + } + ++line_count; + } + } + + virtual bool is_scale() + { + return m_is_scale; + } + + // Это метод вычисления данных, которые нужно отрисовать, приизменении масштаба + // 1. Проверяем размер сырых данных + // - если их больше чем var::MAX_RENDER_SIZE, то делаем сжатие + // - если их меньше, то отрисовка идет полностью и fill_ox уже заполнен так как надо и при масштабировании ни чего не пересчитывается is_scale + virtual void refresh(ImPlotRect current_limits) + { + // кол-во данных, которые мы сейчас хотим отрисовать, когда поменяли масштаб + auto total_dots_for_render = current_limits.Size().x; + // тоже, что начальный m_step, но если m_step меняется, то этот постоянный + // т.е. это максимальный коефиниент сужения графика + std::size_t k1 = m_result.m_size / m_size + 1; + // на сколько изменилось кол-во точек, которые нужно отрисовать + std::size_t k2 = var::MAX_RENDER_SIZE / total_dots_for_render - 1.f; + + // стэк условий, котолрые ограничивают лишние расчеты и сохраняют текущие данные + if (k1 <= k2 && k2 != 0) return; + if (m_past_k2 == k2 && k2 != 0) return; + m_past_k2 = k2; + + // сколько сместилось точке отрисовки во время масштабирования за экран (влево) + std::size_t skip_dots = current_limits.Min().x; + // кол-во точек, которые нужно пропустить из сырых данных чтобы они не были отрисованы во время масштабирования + std::size_t pos = skip_dots * (m_step + k2); + // шаг пропуска, по которому делаем сужение графика + m_step = k1 - k2; + + std::size_t line_count = 0; + for (auto& gd : m_line_data) + { + std::size_t index = pos; + for (auto& g : gd) + { + float tmp_e = 0.f; + for (std::size_t j = index - m_step; j < index; ++j) + { + auto e = m_result.m_data[line_count][j].m_value; + // основной критерий сужения: берем максимальный элемент из данного интервала m_step + tmp_e = hack::math::max_abs(e, tmp_e); + } + g = tmp_e; + + index += m_step; + if (index > m_result.m_size) index = m_result.m_size; + } + ++line_count; + } + + // нужно передать смещение для установки градации + fill_ox(skip_dots); + } + }; +} + + diff --git a/src/monitor/utils/plugins/magnitude.hpp b/src/monitor/utils/plugins/magnitude.hpp new file mode 100644 index 0000000..f69aca4 --- /dev/null +++ b/src/monitor/utils/plugins/magnitude.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include "monitor/utils/plugin.hpp" + +namespace monitor::utils::plugins +{ + struct magnitude : public plugin + { + magnitude() + { + m_type = plugin::TYPE::MAGNITUDE; + m_display_name = "Magnitude"; + } + }; +} + + diff --git a/src/monitor/utils/plugins/raw_data.hpp b/src/monitor/utils/plugins/raw_data.hpp new file mode 100644 index 0000000..3ce4397 --- /dev/null +++ b/src/monitor/utils/plugins/raw_data.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include "monitor/utils/plugin.hpp" + +namespace monitor::utils::plugins +{ + struct raw_data : public plugin + { + raw_data() + { + m_type = plugin::TYPE::RAW_DATA; + m_display_name = "Raw Data"; + } + }; +} + +