Files
monitor/plugin.hpp
2026-03-20 14:44:16 +03:00

188 lines
6.9 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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