121 lines
6.6 KiB
C++
121 lines
6.6 KiB
C++
#pragma once
|
|
#include "../axis/Axis.hpp"
|
|
#include "../render/Blend2D_Cache.hpp"
|
|
#include "../scene/Render_Scene_2D.hpp"
|
|
#include "Plot_Types.hpp"
|
|
#include <expected>
|
|
#include <memory>
|
|
#include <utility>
|
|
#include <vector>
|
|
namespace aethera::render_2d {
|
|
using Spectrum_Frequency = Plot_Coordinate;
|
|
using Spectrum_Power = Plot_Value;
|
|
using Spectrum_Interpolation_Ratio = Plot_Ratio;
|
|
using Spectrum_Marker_Index = Plot_Index;
|
|
using Spectrum_Partition_Mode = Plot_Partition_Mode;
|
|
struct Spectrum_Frame_Tag {};
|
|
struct Spectrum_Frame {
|
|
std::vector<Spectrum_Power> samples{}; /* 最近提交的当前频谱功率样本。 */
|
|
bool operator==(const Spectrum_Frame&) const;
|
|
};
|
|
/* 使用频率轴和功率轴分块准备、绘制当前值、保持曲线及频率标记。 */
|
|
struct Spectrum : Def<Spectrum, Renderable_2D,
|
|
Tagged_Buffer<Spectrum_Frame_Tag, Spectrum_Frame>> {
|
|
using Scene_Object = Impl<Render_Scene_2D>;
|
|
using Frequency_Object = Impl<Frequency_Axis>;
|
|
using Power_Object = Impl<Numeric_Axis>;
|
|
struct Prop : Prev_Prop {
|
|
Prop() { cache_enabled = true; }
|
|
Spectrum_Frequency center_frequency{50.0}; /* 中心频率标记位置,单位为 Hz。 */
|
|
std::size_t partition_count{1}; /* fixed 模式使用的 Prepare 子图分块数。 */
|
|
bool max_hold_visible{}; /* 是否绘制逐点历史最大值曲线。 */
|
|
bool min_hold_visible{}; /* 是否绘制逐点历史最小值曲线。 */
|
|
bool max_marker_visible{}; /* 是否标记当前样本的最大值位置。 */
|
|
bool min_marker_visible{}; /* 是否标记当前样本的最小值位置。 */
|
|
bool sweep_region_visible{}; /* 是否绘制扫频范围背景。 */
|
|
bool visible_range_only{true}; /* 是否裁掉频率轴当前范围外的线段。 */
|
|
Axis_Range frequency_range{}; /* 输入样本首尾对应的有向频率范围,单位为 Hz。 */
|
|
Axis_Range sweep_frequency_range{40.0, 60.0}; /* 扫频背景覆盖的频率范围,单位为 Hz。 */
|
|
Spectrum_Partition_Mode partition_mode{Spectrum_Partition_Mode::automatic}; /* Prepare 子图的分块策略。 */
|
|
Line_Interpolation_Mode interpolation_mode{Line_Interpolation_Mode::linear_value}; /* 相邻样本间的插值规则。 */
|
|
Brush max_brush{}; /* 最大保持曲线下方的填充样式。 */
|
|
Brush current_brush{}; /* 当前频谱曲线下方的填充样式。 */
|
|
Brush min_brush{}; /* 最小保持曲线下方的填充样式。 */
|
|
Pen max_pen{Color::red_color()}; /* 最大保持曲线及最大值标记样式。 */
|
|
Pen current_pen{Color::green_color()}; /* 当前频谱曲线样式。 */
|
|
Pen min_pen{Color::white()}; /* 最小保持曲线及最小值标记样式。 */
|
|
Pen selected_marker_pen{Color{0, 0, 139, 255}, 2.0}; /* 当前选中自定义标记的线条样式。 */
|
|
Pen marker_pen{Color::red_color()}; /* 未选中自定义标记的线条样式。 */
|
|
Pen middle_frequency_pen{Color::red_color()}; /* 中心频率垂线样式。 */
|
|
Brush sweep_region_brush{Color{255, 255, 0, 100}, Brush_Style::solid}; /* 扫频区域背景样式。 */
|
|
std::vector<Spectrum_Frequency> custom_markers{}; /* 自定义频率标记的唯一权威集合,单位为 Hz。 */
|
|
Spectrum_Marker_Index selected_marker{-1}; /* 当前选中标记下标;-1 表示未选择。 */
|
|
bool operator==(const Prop&) const;
|
|
};
|
|
struct State : Prev_State {
|
|
std::size_t sample_count{}; /* 最近一次发布帧的样本数。 */
|
|
std::size_t rendered_point_count{}; /* 最近一次 Prepare 生成的曲线点数。 */
|
|
std::size_t selectable_marker_count{}; /* 当前可选择的自定义标记数。 */
|
|
bool operator==(const State&) const;
|
|
};
|
|
/* 完整声明、分块子图、内部状态操作和 CRTP 分派见 Spectrum.ipp。 */
|
|
struct Private;
|
|
template <typename Object>
|
|
struct Builder : Prev_Builder<Object> {
|
|
using Base = Prev_Builder<Object>;
|
|
Builder(Frequency_Object* frequency_axis, Power_Object* power_axis);
|
|
[[nodiscard]] std::expected<std::unique_ptr<Object>, Dependency_Graph_Error> build();
|
|
private:
|
|
Frequency_Object* frequency_axis{}; /* 不拥有的频率轴;生命周期必须覆盖 Spectrum。 */
|
|
Power_Object* power_axis{}; /* 不拥有的功率轴;生命周期必须覆盖 Spectrum。 */
|
|
};
|
|
enum class Power_At_Result {
|
|
no_samples,
|
|
invalid_frequency_range,
|
|
frequency_out_of_range
|
|
};
|
|
/* 在已发布帧的线性样本位置上查询功率。 */
|
|
[[nodiscard]] std::expected<Spectrum_Power, Power_At_Result> power_at(Spectrum_Frequency frequency) const;
|
|
/* 添加一个自定义频率标记。 */
|
|
void add_custom_marker(Spectrum_Frequency frequency);
|
|
/* 添加一个自定义垂直线标记。 */
|
|
void add_custom_line_marker(Spectrum_Frequency frequency);
|
|
/* 删除与给定频率距离最近的自定义标记。 */
|
|
void remove_custom_marker(Spectrum_Frequency frequency);
|
|
/* 删除当前选中的自定义标记;未选择时不处理。 */
|
|
void remove_selected_marker();
|
|
/* 删除全部自定义标记并清除选择。 */
|
|
void clear_custom_markers();
|
|
/* 返回可选择的自定义线标记数量。 */
|
|
[[nodiscard]] std::size_t selectable_line_marker_count() const;
|
|
/* 返回当前选中标记下标;-1 表示未选择。 */
|
|
[[nodiscard]] Spectrum_Marker_Index selected_marker_index() const;
|
|
/* 选择指定下标;越界值清除选择。 */
|
|
void set_selected_marker_index(Spectrum_Marker_Index index);
|
|
/* 循环选择下一个标记;无标记时清除选择。 */
|
|
void select_next_marker();
|
|
/* 循环选择上一个标记;无标记时清除选择。 */
|
|
void select_previous_marker();
|
|
/* 清除当前标记选择。 */
|
|
void clear_marker_selection();
|
|
enum class Marker_Frequency_Result {
|
|
index_out_of_range
|
|
};
|
|
/* 查询指定标记的频率。 */
|
|
[[nodiscard]] std::expected<Spectrum_Frequency, Marker_Frequency_Result> marker_frequency(Spectrum_Marker_Index index) const;
|
|
enum class Set_Marker_Frequency_Result {
|
|
updated,
|
|
index_out_of_range
|
|
};
|
|
/* 修改指定标记频率。 */
|
|
[[nodiscard]] Set_Marker_Frequency_Result set_marker_frequency(Spectrum_Marker_Index index, Spectrum_Frequency frequency);
|
|
enum class Set_Current_Marker_Frequency_Result {
|
|
updated,
|
|
no_selection
|
|
};
|
|
/* 修改当前选中标记频率。 */
|
|
[[nodiscard]] Set_Current_Marker_Frequency_Result set_current_marker_frequency(Spectrum_Frequency frequency);
|
|
};
|
|
}
|
|
#include "Spectrum.ipp"
|