Files
Renderive/Core/plottable/Sweep_Spectrum_p.h
T
2026-08-02 18:58:35 +08:00

106 lines
4.6 KiB
C++

#pragma once
#include "../Axis/Axis_p.h"
#include "../architecture/Bounded_Input_Buffer.h"
#include "../base/Frame_Memory.h"
#include "../base/Geometry.h"
#include "../base/Style.h"
#include "../event/Pointer_Event.h"
#include "../render/Canvas.h"
#include "../primitive/Curve.h"
#include "../primitive/Curve_Utils_p.h"
#include "Sweep_Spectrum.h"
namespace renderive {
struct Sweep_Spectrum_Render_State : renderive::Render_State, Sweep_Spectrum_Prop {};
struct Sweep_Spectrum_Input_Data : renderive::Input_Data {
static constexpr std::size_t Latest_Only_Count = 1;
Bounded_Vector_Double_Input_Buffer data;
void clear() override {
data.clear();
}
};
struct Sweep_Spectrum_Private : renderive::Typed_Render_Data<Sweep_Spectrum, Sweep_Spectrum_Render_State, Sweep_Spectrum_Input_Data> {
std::vector<PointF> sweep_points;
int next_block_index{};
int bins_per_block{};
int block_count{};
Range frequency_range;
bool first_sweep_incomplete = true;
void reset_sweep_grid(int block_frequency_point_size, int block_num, Range frequency_range) {
this->bins_per_block = block_frequency_point_size;
this->block_count = block_num;
this->frequency_range = frequency_range;
int total_point_count = block_num * block_frequency_point_size;
if (total_point_count <= 0) {
sweep_points.clear();
first_sweep_incomplete = true;
return;
}
sweep_points.resize(total_point_count);
int interval_count = total_point_count - 1;
if (interval_count == 0) {
sweep_points[0].x = frequency_range.origin;
first_sweep_incomplete = true;
return;
}
double step = frequency_range.length() / interval_count;
double frequency = frequency_range.origin;
for (int i = 0; i < interval_count; ++i) {
sweep_points[i].x = frequency;
frequency += step;
}
sweep_points.back().x = frequency_range.target;
first_sweep_incomplete = true;
}
void prepare_data(const Render_Frame_Snapshot&, const Renderable_Frame_View& frame_view) override {
Sweep_Spectrum_Render_State* s = render_state(frame_view);
Sweep_Spectrum_Input_Data* d = render_input_data(frame_view);
if (!s || !d)
return;
if (
bins_per_block != s->bins_per_block ||
block_count != s->block_num ||
frequency_range != s->frequency_range) {
reset_sweep_grid(s->bins_per_block, s->block_num, s->frequency_range);
next_block_index = 0;
}
d->data.read_all([this, d](const auto& data) {
if ((int)data.size() != bins_per_block || sweep_points.empty()) {
return;
}
PointF* start = &sweep_points[next_block_index * bins_per_block];
for (int i = 0; i < bins_per_block; ++i) {
start[i].y = data[i];
}
next_block_index++;
if (next_block_index == block_count) {
next_block_index = 0;
first_sweep_incomplete = false;
}
});
frame_view.consume_input();
}
void draw(Canvas& canvas, const Render_Frame_Snapshot& snapshot, const Renderable_Frame_View& frame_view) override {
Sweep_Spectrum_Render_State* s = render_state(frame_view);
if (!s)
return;
auto frequency_axis = s->frequency_axis.lock();
auto power_axis = s->power_axis.lock();
if (!frequency_axis || !power_axis)
return;
Axis_Mapping_2D mapping = Axis_Render_Access::mapping(frequency_axis.get(), power_axis.get(), snapshot);
int total_point_count = (int)sweep_points.size();
int available_count = !first_sweep_incomplete ? total_point_count : next_block_index * bins_per_block;
std::pmr::vector<PointF> data(frame_memory_resource());
data = Curve_Utils::build_resampled_points(mapping, s->frequency_range, total_point_count, available_count, s->visible_range_only, s->interpolation_mode, [this](int i) {
return sweep_points.at(i).y;
});
Curve_Utils::draw_polyline(&canvas, data, s->pen);
canvas.set_pen(s->current_frequency_pen);
double current_frequency = block_count > 1 ? frequency_range.origin + next_block_index * frequency_range.length() / (block_count - 1.0) : frequency_range.origin;
canvas.draw_line(
mapping.map(current_frequency, mapping.value.coord_range.origin),
mapping.map(current_frequency, mapping.value.coord_range.target));
}
};
} // namespace renderive