add intefaces plugins

This commit is contained in:
2026-03-20 14:44:16 +03:00
parent e59fd990a1
commit cfa39f850b
18 changed files with 723 additions and 87 deletions

187
plugin.hpp Normal file
View File

@@ -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<hr::fvec_t> 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);
}
};
}

187
plugin.t.hpp Normal file
View File

@@ -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<hr::fvec_t> 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);
}
};
}

View File

@@ -15,9 +15,17 @@ headers = [
'monitor/gui/components/base_plugins/base_plugins.hpp', 'monitor/gui/components/base_plugins/base_plugins.hpp',
'monitor/gui/components/base_controls/base_controls.hpp', 'monitor/gui/components/base_controls/base_controls.hpp',
'monitor/gui/components/graph/graph.hpp', 'monitor/gui/components/graph/graph.hpp',
'monitor/gui/components/fft_scaled/fft_scaled.hpp',
############ UTILS ############ UTILS
'monitor/utils/var.hpp', '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/audio/audio.hpp',
'monitor/libs/gtkfd/gtkfd.hpp', 'monitor/libs/gtkfd/gtkfd.hpp',
@@ -78,6 +86,11 @@ sources = [
'monitor/gui/components/graph/cpp/on_event.cpp', 'monitor/gui/components/graph/cpp/on_event.cpp',
'monitor/gui/components/graph/cpp/render.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 # win/tabs/snapshot/base_controls
'monitor/gui/components/base_controls/cpp/base.cpp', 'monitor/gui/components/base_controls/cpp/base.cpp',
'monitor/gui/components/base_controls/cpp/on_event.cpp', 'monitor/gui/components/base_controls/cpp/on_event.cpp',

View File

@@ -2,6 +2,7 @@
#include <VE.hpp> #include <VE.hpp>
#include "monitor/gui/components/graph/graph.hpp" #include "monitor/gui/components/graph/graph.hpp"
#include "monitor/gui/components/fft_scaled/fft_scaled.hpp"
namespace monitor::components namespace monitor::components
{ {
@@ -16,16 +17,15 @@ namespace monitor::components
ImVec2 m_pos = { 4.f, 70.f }; ImVec2 m_pos = { 4.f, 70.f };
ImGuiTabBarFlags m_tab_bar_flags { ImGuiTabBarFlags_None }; ImGuiTabBarFlags m_tab_bar_flags { ImGuiTabBarFlags_None };
std::size_t m_current_open_index = 0; std::size_t m_current_open_index = 0;
graph m_graph;
std::string m_snapshot_id; std::string m_snapshot_id;
private:
graph m_graph;
// fft_scaled m_fft_scaled;
private: private:
hr::setup m_setup; hr::setup m_setup;
std::vector<std::shared_ptr<utils::plugin>> m_base_plugins = { std::vector<std::shared_ptr<utils::plugin>> m_base_plugins;
std::make_shared<utils::plugin>(utils::plugin{ .m_type = utils::plugin::TYPE::RAW_DATA, .m_display_name = "Raw Data"}),
std::make_shared<utils::plugin>(utils::plugin{ .m_type = utils::plugin::TYPE::MAGNITUDE, .m_display_name = "Magnitude"}),
std::make_shared<utils::plugin>(utils::plugin{ .m_type = utils::plugin::TYPE::ENERGY, .m_display_name = "Energy"}),
};
public: public:
void init(std::string snapshot_id, hr::setup setup); void init(std::string snapshot_id, hr::setup setup);

View File

@@ -1,4 +1,6 @@
#include "monitor/gui/components/base_plugins/base_plugins.hpp" #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 namespace monitor::components
{ {
@@ -7,6 +9,11 @@ namespace monitor::components
CONNECT(this); CONNECT(this);
m_graph.on_attach(); m_graph.on_attach();
// m_fft_scaled.on_attach();
m_base_plugins.push_back(std::make_shared<utils::plugin>(utils::plugins::raw_data{}));
m_base_plugins.push_back(std::make_shared<utils::plugin>(utils::plugins::magnitude{}));
m_size.x = VE::application::get()->get_glfw()->width() - VE::application::get()->get_glfw()->width() / 4.f; 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; m_size.y = VE::application::get()->get_glfw()->height() / 2.f;
} }
@@ -15,11 +22,13 @@ namespace monitor::components
{ {
DISCONNECT(); DISCONNECT();
m_graph.on_detach(); m_graph.on_detach();
// m_fft_scaled.on_detach();
} }
void base_plugins::update() void base_plugins::update()
{ {
m_graph.update(); m_graph.update();
// m_fft_scaled.update();
} }
void base_plugins::init(std::string snapshot_id, hr::setup setup) void base_plugins::init(std::string snapshot_id, hr::setup setup)
@@ -28,5 +37,7 @@ namespace monitor::components
m_setup = setup; m_setup = setup;
m_graph.init(m_snapshot_id, m_setup); m_graph.init(m_snapshot_id, m_setup);
m_graph.set_plugin(m_base_plugins[0]); m_graph.set_plugin(m_base_plugins[0]);
// m_fft_scaled.init(m_snapshot_id, m_setup);
} }
} }

View File

@@ -31,6 +31,8 @@ namespace monitor::components
ImGui::EndTabBar(); ImGui::EndTabBar();
} }
// m_fft_scaled.render();
utils::func::draw_border(m_size); utils::func::draw_border(m_size);
ImGui::EndChild(); ImGui::EndChild();

View File

@@ -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<hr::plugins::fft>(m_setup);
m_plugin.init();
m_plugin.fill();
}
}

View File

@@ -0,0 +1,8 @@
#include "monitor/gui/components/fft_scaled/fft_scaled.hpp"
namespace monitor::components
{
void fft_scaled::on_event(VE::event& e)
{
}
}

View File

@@ -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();
}
}
}

View File

@@ -0,0 +1,28 @@
#pragma once
#include <VE.hpp>
#include <harmonica.hpp>
#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;
};
}

View File

@@ -46,7 +46,7 @@ namespace monitor::components
} }
if (!m_plugin->empty()) if (!m_plugin->empty())
{ {
m_plugin->graph_init(); m_plugin->init();
m_plugin->fill(); m_plugin->fill();
} }
else else
@@ -62,7 +62,7 @@ namespace monitor::components
if (m_current_limits.Min().x != current_limits.Min().x) if (m_current_limits.Min().x != current_limits.Min().x)
{ {
m_current_limits = current_limits; m_current_limits = current_limits;
m_plugin->fill(m_current_limits); m_plugin->refresh(m_current_limits);
} }
} }
} }

View File

@@ -18,19 +18,19 @@ namespace monitor::components
ImPlotAxisFlags_NoTickLabels // текстовые надписи отображаться не будут ImPlotAxisFlags_NoTickLabels // текстовые надписи отображаться не будут
); );
ImPlot::SetupAxisLimits(ImAxis_X1, 0.f, m_plugin->m_graph.m_size); ImPlot::SetupAxisLimits(ImAxis_X1, 0.f, m_plugin->m_size);
ImPlot::SetupAxisLimits(ImAxis_Y1, 0.f, m_plugin->m_graph.m_max_element + 2.f); ImPlot::SetupAxisLimits(ImAxis_Y1, 0.f, m_plugin->m_result.m_max + 2.f);
ImPlot::SetupAxisLimitsConstraints(ImAxis_X1, 0, INFINITY); ImPlot::SetupAxisLimitsConstraints(ImAxis_X1, 0, INFINITY);
ImPlot::SetupLegend(ImPlotLocation_NorthEast); ImPlot::SetupLegend(ImPlotLocation_NorthEast);
refresh(ImPlot::GetPlotLimits()); 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) 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 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; m_is_first_render = false;

View File

@@ -10,8 +10,6 @@ namespace monitor::components
m_base_controls.on_attach(); m_base_controls.on_attach();
// HERE // HERE
// то что ниже будем убирать // то что ниже будем убирать
m_audio.on_attach(); m_audio.on_attach();

View File

@@ -6,7 +6,6 @@ namespace monitor::components
void tabs::on_attach() void tabs::on_attach()
{ {
CONNECT(this); CONNECT(this);
for (auto & s : m_snapshots) s->on_attach();
} }
void tabs::on_detach() void tabs::on_detach()
@@ -26,8 +25,8 @@ namespace monitor::components
void tabs::create_snapshot(hr::setup setup) void tabs::create_snapshot(hr::setup setup)
{ {
auto s = std::make_shared<snapshot>(); auto s = std::make_shared<snapshot>();
s->init(setup);
s->on_attach(); s->on_attach();
s->init(setup);
m_snapshots.push_back(s); m_snapshots.push_back(s);
VE::event e { utils::event_type::CREATE_SNAPSHOT_COMPLETED, nullptr }; VE::event e { utils::event_type::CREATE_SNAPSHOT_COMPLETED, nullptr };

View File

@@ -8,10 +8,15 @@ namespace monitor::utils
{ {
struct plugin struct plugin
{ {
public:
plugin() = default;
virtual ~plugin() = default;
public: public:
enum class TYPE enum class TYPE
{ {
RAW_DATA, RAW_DATA,
FFT,
MAGNITUDE, MAGNITUDE,
ENERGY ENERGY
}; };
@@ -19,57 +24,42 @@ namespace monitor::utils
public: public:
hr::result m_result; hr::result m_result;
TYPE m_type; 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<hr::fvec_t> m_line_data;
// говорит нужно ли делать сжатие графика ли нет
bool m_is_scale = false;
std::string m_display_name; std::string m_display_name;
std::size_t m_step = 0;
// это кол-во точек, которые нужно отрисовать с учетом текущего масштаба но в прошлом шаге
std::size_t m_past_k2 = 0;
public: public:
struct graph virtual bool empty() { return m_result.empty(); }
{
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<hr::fvec_t> m_data;
// говорит нужно ли делать сжатие графика ли нет
bool m_is_scale = false;
void fill_ox(std::size_t start_pos = 0) virtual void init()
{
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 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"); 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_is_scale = raw_size > var::MAX_RENDER_SIZE;
m_graph.m_size = std::min(raw_size, var::MAX_RENDER_SIZE); m_size = std::min(raw_size, var::MAX_RENDER_SIZE);
m_graph.m_line_count = m_result.m_data.size(); m_line_count = m_result.m_data.size();
m_graph.init(); m_line_data.reserve(m_line_count);
m_graph.fill_ox(); 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) 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; std::size_t line_count = 0;
for (auto& gd : m_graph.m_data) for (auto& gd : m_line_data)
{ {
std::size_t index = 0; std::size_t index = 0;
for (auto& g : gd) for (auto& g : gd)
@@ -98,10 +94,8 @@ namespace monitor::utils
tmp_e = hack::math::max_abs(e, tmp_e); tmp_e = hack::math::max_abs(e, tmp_e);
} }
g = 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; 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; ++line_count;
} }
@@ -109,47 +103,43 @@ namespace monitor::utils
else else
{ {
// заполняется, когда данных пришло меньше чем нужно для полного рендеринга // заполняется, когда данных пришло меньше чем нужно для полного рендеринга
std::size_t graph_count = 0; std::size_t line_count = 0;
for (auto el : m_result.m_data) for (auto el : m_result.m_data)
{ {
std::size_t index = 0; std::size_t index = 0;
for (auto e : el) for (auto e : el)
{ {
m_graph.m_max_element = hack::math::max(e.m_value, m_graph.m_max_element); m_line_data[line_count][index] = e.m_value;
m_graph.m_data[graph_count][index] = e.m_value;
++index; ++index;
} }
++graph_count; ++line_count;
} }
} }
} }
std::size_t m_local_k2 = 0; virtual bool is_scale()
std::size_t m_step;
bool is_scale()
{ {
return m_graph.m_is_scale; return m_is_scale;
} }
// Это основной меод вычисления данных, которые нужно отрисовать // Это метод вычисления данных, которые нужно отрисовать, приизменении масштаба
// 1. Проверяем размер сырых данных // 1. Проверяем размер сырых данных
// - если их больше чем var::MAX_RENDER_SIZE, то делаем сжатие // - если их больше чем var::MAX_RENDER_SIZE, то делаем сжатие
// - если их меньше, то отрисовка идет полностью и fill_ox уже заполнен так как надо и при масштабировании ни чего не пересчитывается is_scale // - если их меньше, то отрисовка идет полностью и fill_ox уже заполнен так как надо и при масштабировании ни чего не пересчитывается is_scale
void fill(ImPlotRect current_limits) virtual void refresh(ImPlotRect current_limits)
{ {
// кол-во данных, которые мы сейчас хотим отрисовать, когда поменяли масштаб // кол-во данных, которые мы сейчас хотим отрисовать, когда поменяли масштаб
auto total_dots_for_render = current_limits.Size().x; auto total_dots_for_render = current_limits.Size().x;
// тоже, что начальный m_step, но если m_step меняется, то этот постоянный // тоже, что начальный 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; std::size_t k2 = var::MAX_RENDER_SIZE / total_dots_for_render - 1.f;
// стэк условий, котолрые ограничивают лишние расчеты и сохраняют текущие данные // стэк условий, которые ограничивают лишние расчеты и сохраняют текущие данные
if (k1 <= k2 && k2 != 0) return; if (k1 <= k2 && k2 != 0) return;
if (m_local_k2 == k2 && k2 != 0) return; if (m_past_k2 == k2 && k2 != 0) return;
m_local_k2 = k2; m_past_k2 = k2;
// сколько сместилось точке отрисовки во время масштабирования за экран (влево) // сколько сместилось точке отрисовки во время масштабирования за экран (влево)
std::size_t skip_dots = current_limits.Min().x; std::size_t skip_dots = current_limits.Min().x;
@@ -159,7 +149,7 @@ namespace monitor::utils
m_step = k1 - k2; m_step = k1 - k2;
std::size_t line_count = 0; std::size_t line_count = 0;
for (auto& gd : m_graph.m_data) for (auto& gd : m_line_data)
{ {
std::size_t index = pos; std::size_t index = pos;
for (auto& g : gd) for (auto& g : gd)
@@ -172,16 +162,14 @@ namespace monitor::utils
tmp_e = hack::math::max_abs(e, tmp_e); tmp_e = hack::math::max_abs(e, tmp_e);
} }
g = 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; 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; ++line_count;
} }
// нужно передать смещение для установки градации // нужно передать смещение для установки градации
m_graph.fill_ox(skip_dots); fill_ox(skip_dots);
} }
}; };
} }

View File

@@ -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);
}
};
}

View File

@@ -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";
}
};
}

View File

@@ -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";
}
};
}