#include "Sweep_Spectrum.h" #include "Curve_Sampling.h" #include "Plottable_Real_Time_Data.h" #include "../render/Blend2D_Cache.h" #include #include #include namespace renderive { namespace detail { namespace { using Sweep_Spectrum_History = Plottable_History_Real_Time_Data, std::deque>>; std::vector flatten(const std::deque>& blocks) { std::vector values; for(const auto& block : blocks) values.insert(values.end(), block.begin(), block.end()); return values; } } struct Sweep_Spectrum_Control::Impl { struct Prepare_Buffer { std::vector points; PointF current_first; PointF current_second; bool valid{}; }; Impl(Sweep_Spectrum_Control& owner, renderive_Owner frequency, renderive_Owner power) : frequency_axis(std::move(frequency)), power_axis(std::move(power)), blocks(owner) {} renderive_Owner frequency_axis; renderive_Owner power_axis; Sweep_Spectrum_History blocks; Prepare_Buffer prepare_buffer; }; Sweep_Spectrum_Control::Sweep_Spectrum_Control(const Sweep_Spectrum_Properties& properties, renderive_Owner frequency_axis, renderive_Owner power_axis) : Plottable_State(properties), impl_(std::make_unique(*this, std::move(frequency_axis), std::move(power_axis))) {} Sweep_Spectrum_Control::~Sweep_Spectrum_Control() = default; void Sweep_Spectrum_Control::append_block(std::span values) { if(get<&Sweep_Spectrum_Properties::bins_per_block>() <= 0) set<&Sweep_Spectrum_Properties::bins_per_block>(static_cast(values.size())); const int limit = get<&Sweep_Spectrum_Properties::block_count>(); impl_->blocks.update({values.begin(), values.end()}, static_cast(limit)); changed(); } void Sweep_Spectrum_Control::append_block(std::pmr::vector&& values) { append_block(std::span(values.data(), values.size())); } std::size_t Sweep_Spectrum_Control::stored_block_count() const { return impl_->blocks.size(); } std::size_t Sweep_Spectrum_Control::stored_point_count() const { const auto blocks = impl_->blocks.snapshot(); std::size_t count{}; for(const auto& block : blocks) count += block.size(); return count; } std::size_t Sweep_Spectrum_Control::rendered_point_count() const { const auto state = properties(); const auto values = flatten(impl_->blocks.snapshot()); return curve_points(values, state.frequency_range, impl_->frequency_axis->transform(), impl_->power_axis->transform(), state.visible_range_only, state.interpolation_mode).size(); } void Sweep_Spectrum_Control::publish() { publish_properties(); const int limit = get<&Sweep_Spectrum_Properties::block_count>(); impl_->blocks.retain_latest(static_cast(limit)); } void Sweep_Spectrum_Control::prepare_frame(const Prepare_Render_Context& context) { const auto& view = context.frame.render_state; const auto& state = render_properties(view); const auto& blocks = view.get(impl_->blocks); const auto values = flatten(blocks); auto& output = impl_->prepare_buffer; output = {}; if (values.size() < 2) return; const Axis_Transform x = impl_->frequency_axis->transform(view); const Axis_Transform y = impl_->power_axis->transform(view); output.points = curve_points(values, state.frequency_range, x, y, state.visible_range_only, state.interpolation_mode); const double completed = std::min(1.0, static_cast(blocks.size()) / state.block_count.get()); const double frequency = state.frequency_range.origin + state.frequency_range.length() * completed; output.current_first = mapped_point(x, frequency, y, y.coordinate_range.origin); output.current_second = mapped_point(x, frequency, y, y.coordinate_range.target); output.valid = true; } void Sweep_Spectrum_Control::paint(Painter& painter, const Paint_Render_Context& context) { const auto& output = impl_->prepare_buffer; if (!output.valid) return; const auto& view = context.frame.render_state; const auto& state = render_properties(view); painter.polyline(output.points, state.pen); painter.line(output.current_first, output.current_second, state.current_frequency_pen); } } }