Files
Renderive/Core2/plottable/Plottables.h
T
2026-08-11 06:21:51 +08:00

549 lines
23 KiB
C++

#pragma once
#include "../axis/Axis.h"
#include "Hover_Tooltip.h"
#include <chrono>
#include <deque>
#include <memory_resource>
#include <span>
#include <vector>
namespace renderive {
class LIB_DECL Spectrum final : public Renderable, public Event_Handler,
public Hover_Tooltip_Mixin<Spectrum> {
public:
Spectrum(Plot_Core& plot, std::shared_ptr<Frequency_Axis> frequency_axis,
std::shared_ptr<Axis> power_axis);
[[nodiscard]] std::shared_ptr<Frequency_Axis> frequency_axis() const;
void set_frequency_axis(std::shared_ptr<Frequency_Axis> value);
[[nodiscard]] std::shared_ptr<Axis> power_axis() const;
void set_power_axis(std::shared_ptr<Axis> value);
[[nodiscard]] int frequency_point_size() const;
void set_frequency_point_size(int value);
[[nodiscard]] Range frequency_range() const;
void set_frequency_range(Range value);
[[nodiscard]] double center_frequency() const;
void set_center_frequency(double value);
[[nodiscard]] Range sweep_frequency_range() const;
void set_sweep_frequency_range(Range value);
[[nodiscard]] bool max_hold_visible() const;
void set_max_hold_visible(bool value);
[[nodiscard]] bool min_hold_visible() const;
void set_min_hold_visible(bool value);
[[nodiscard]] bool max_marker_visible() const;
void set_max_marker_visible(bool value);
[[nodiscard]] bool use_min_marker() const;
void set_use_min_marker(bool value);
[[nodiscard]] bool sweep_region_visible() const;
void set_sweep_region_visible(bool value);
[[nodiscard]] bool visible_range_only() const;
void set_visible_range_only(bool value);
[[nodiscard]] Line_Interpolation_Mode interpolation_mode() const;
void set_interpolation_mode(Line_Interpolation_Mode value);
[[nodiscard]] Brush max_brush() const;
void set_max_brush(Brush value);
[[nodiscard]] Brush current_brush() const;
void set_current_brush(Brush value);
[[nodiscard]] Brush min_brush() const;
void set_min_brush(Brush value);
[[nodiscard]] Pen max_pen() const;
void set_max_pen(Pen value);
[[nodiscard]] Pen current_pen() const;
void set_current_pen(Pen value);
[[nodiscard]] Pen min_pen() const;
void set_min_pen(Pen value);
[[nodiscard]] Pen selected_marker_pen() const;
void set_selected_marker_pen(Pen value);
[[nodiscard]] Pen marker_pen() const;
void set_marker_pen(Pen value);
[[nodiscard]] Pen middle_frequency_pen() const;
void set_middle_frequency_pen(Pen value);
[[nodiscard]] Brush sweep_region_brush() const;
void set_sweep_region_brush(Brush value);
void update_samples(std::span<const double> values);
void update_samples(std::pmr::vector<double>&& values);
template <class Values> void update_samples(const Values& values) {
update_samples(std::span<const double>(values.data(), values.size()));
}
[[nodiscard]] std::size_t sample_count() const;
[[nodiscard]] std::size_t rendered_point_count() const;
[[nodiscard]] double power_at(double frequency, bool& ok) const;
void add_custom_marker(double frequency);
void add_custom_line_marker(double frequency);
void remove_custom_marker(double frequency);
void remove_selected_marker();
void clear_custom_markers();
[[nodiscard]] int selectable_line_marker_count() const;
[[nodiscard]] int selected_marker_index() const;
void set_selected_marker_index(int index);
void select_next_marker();
void select_previous_marker();
void clear_marker_selection();
[[nodiscard]] double marker_frequency(int index) const;
void set_marker_frequency(int index, double frequency);
void set_current_marker_frequency(double frequency);
void handle_event(const Event& event) override;
void tooltip_changed() { changed(); }
class Builder {
public:
Builder(std::shared_ptr<Renderable> parent,
std::shared_ptr<Frequency_Axis> frequency_axis,
std::shared_ptr<Axis> power_axis);
Builder& set_frequency_range(Range value) { frequency_range_ = value; return *this; }
Builder& set_frequency_point_size(int value) { point_count_ = value; return *this; }
Builder& set_center_frequency(double value) { center_ = value; return *this; }
Builder& set_sweep_frequency_range(Range value) { sweep_range_ = value; return *this; }
Builder& set_max_hold_visible(bool value) { max_hold_ = value; return *this; }
Builder& set_min_hold_visible(bool value) { min_hold_ = value; return *this; }
Builder& set_max_marker_visible(bool value) { max_marker_ = value; return *this; }
Builder& set_use_min_marker(bool value) { min_marker_ = value; return *this; }
Builder& set_sweep_region_visible(bool value) { sweep_visible_ = value; return *this; }
Builder& set_visible_range_only(bool value) { visible_only_ = value; return *this; }
Builder& set_interpolation_mode(Line_Interpolation_Mode value) { interpolation_ = value; return *this; }
std::shared_ptr<Spectrum> build();
private:
std::shared_ptr<Renderable> parent_;
std::shared_ptr<Frequency_Axis> frequency_axis_;
std::shared_ptr<Axis> power_axis_;
Range frequency_range_{};
int point_count_{};
double center_ = 50.0;
Range sweep_range_{40.0, 60.0};
bool max_hold_{};
bool min_hold_{};
bool max_marker_{};
bool min_marker_{};
bool sweep_visible_{};
bool visible_only_{true};
Line_Interpolation_Mode interpolation_ = Line_Interpolation_Mode::Linear_Value;
};
protected:
void paint(detail::Painter& painter) override;
private:
struct State {
std::shared_ptr<Frequency_Axis> frequency_axis;
std::shared_ptr<Axis> power_axis;
int point_count{};
Range frequency_range{};
double center_frequency = 50.0;
Range sweep_range{40.0, 60.0};
bool max_hold{};
bool min_hold{};
bool max_marker{};
bool min_marker{};
bool sweep_visible{};
bool visible_only{true};
Line_Interpolation_Mode interpolation = Line_Interpolation_Mode::Linear_Value;
Brush max_brush;
Brush current_brush;
Brush min_brush;
Pen max_pen{Color::red()};
Pen current_pen{Color::green()};
Pen min_pen{Color::white()};
Pen selected_marker_pen{Color{0, 0, 139, 255}, 2.0};
Pen marker_pen{Color::red()};
Pen middle_pen{Color::red()};
Brush sweep_brush{Color{255, 255, 0, 100}, Brush_Style::Solid};
std::vector<double> samples;
std::vector<double> maxima;
std::vector<double> minima;
std::vector<double> markers;
int selected_marker = -1;
};
[[nodiscard]] State state_snapshot() const;
mutable std::mutex mutex_;
State state_;
};
class LIB_DECL Waterfall final : public Renderable, public Event_Handler,
public Hover_Tooltip_Mixin<Waterfall> {
public:
Waterfall(Plot_Core& plot, std::shared_ptr<Frequency_Axis> frequency_axis,
std::shared_ptr<Time_Axis> time_axis);
void append_row(int tick, std::span<const double> values);
void append_row(int tick, std::pmr::vector<double>&& values);
void append_row(Time_Of_Day time, std::span<const double> values);
void append_row(Time_Of_Day time, std::pmr::vector<double>&& values);
template <class Values> void append_row(Time_Of_Day time, const Values& values) {
append_row(time, std::span<const double>(values.data(), values.size()));
}
[[nodiscard]] std::shared_ptr<Frequency_Axis> frequency_axis() const;
[[nodiscard]] std::shared_ptr<Time_Axis> time_axis() const;
[[nodiscard]] Range frequency_range() const;
void set_frequency_range(Range value);
[[nodiscard]] Range power_range() const;
void set_power_range(Range value);
[[nodiscard]] int frequency_bin_count() const;
void set_frequency_bin_count(int value);
[[nodiscard]] std::size_t row_count() const;
[[nodiscard]] std::size_t stored_point_count() const;
[[nodiscard]] std::size_t rendered_cell_count() const;
[[nodiscard]] bool visible_range_only() const;
void set_visible_range_only(bool value);
[[nodiscard]] Image_Interpolation_Mode interpolation_mode() const;
void set_interpolation_mode(Image_Interpolation_Mode value);
void handle_event(const Event& event) override;
void tooltip_changed() { changed(); }
class Builder {
public:
Builder(std::shared_ptr<Renderable> parent,
std::shared_ptr<Frequency_Axis> frequency_axis,
std::shared_ptr<Time_Axis> time_axis);
Builder& set_frequency_range(Range value) { frequency_range_ = value; return *this; }
Builder& set_power_range(Range value) { power_range_ = value; return *this; }
Builder& set_frequency_bin_count(int value) { bin_count_ = value; return *this; }
Builder& set_visible_range_only(bool value) { visible_only_ = value; return *this; }
Builder& set_interpolation_mode(Image_Interpolation_Mode value) { interpolation_ = value; return *this; }
Builder& set_color_map(Color_Map value) { color_map_ = std::move(value); return *this; }
std::shared_ptr<Waterfall> build();
private:
std::shared_ptr<Renderable> parent_;
std::shared_ptr<Frequency_Axis> frequency_axis_;
std::shared_ptr<Time_Axis> time_axis_;
Range frequency_range_{0.0, 10.0};
Range power_range_{0.0, 10.0};
int bin_count_{};
bool visible_only_{true};
Image_Interpolation_Mode interpolation_ = Image_Interpolation_Mode::Nearest;
Color_Map color_map_;
};
protected:
void paint(detail::Painter& painter) override;
private:
struct Row { int tick{}; std::vector<double> values; };
struct State {
std::shared_ptr<Frequency_Axis> frequency_axis;
std::shared_ptr<Time_Axis> time_axis;
Range frequency_range{0.0, 10.0};
Range power_range{0.0, 10.0};
int bin_count{};
bool visible_only{true};
Image_Interpolation_Mode interpolation = Image_Interpolation_Mode::Nearest;
Color_Map color_map;
std::deque<Row> rows;
};
[[nodiscard]] State state_snapshot() const;
mutable std::mutex mutex_;
State state_;
};
class LIB_DECL Frequency_Trace final : public Renderable {
public:
Frequency_Trace(Plot_Core& plot, std::shared_ptr<Time_Axis> time_axis,
std::shared_ptr<Axis> value_axis);
void append_sample(int tick, double value);
void append_sample(Time_Of_Day time, double value);
[[nodiscard]] std::shared_ptr<Time_Axis> time_axis() const;
[[nodiscard]] std::shared_ptr<Axis> value_axis() const;
[[nodiscard]] std::size_t sample_count() const;
[[nodiscard]] std::size_t rendered_point_count() const;
class Builder {
public:
Builder(std::shared_ptr<Renderable> parent, std::shared_ptr<Time_Axis> time_axis,
std::shared_ptr<Axis> value_axis);
Builder& set_color(Color value) { pen_.color = value; return *this; }
Builder& set_pen(Pen value) { pen_ = value; return *this; }
std::shared_ptr<Frequency_Trace> build();
private:
std::shared_ptr<Renderable> parent_;
std::shared_ptr<Time_Axis> time_axis_;
std::shared_ptr<Axis> value_axis_;
Pen pen_{Color::yellow()};
};
protected:
void paint(detail::Painter& painter) override;
private:
mutable std::mutex mutex_;
std::shared_ptr<Time_Axis> time_axis_;
std::shared_ptr<Axis> value_axis_;
Pen pen_{Color::yellow()};
std::deque<std::pair<int, double>> samples_;
};
class LIB_DECL Afterglow final : public Renderable {
public:
Afterglow(Plot_Core& plot, std::shared_ptr<Frequency_Axis> frequency_axis,
std::shared_ptr<Axis> power_axis);
[[nodiscard]] std::shared_ptr<Frequency_Axis> frequency_axis() const;
[[nodiscard]] std::shared_ptr<Axis> power_axis() const;
[[nodiscard]] Range frequency_range() const;
void set_frequency_range(Range value);
[[nodiscard]] Range power_range() const;
void set_power_range(Range value);
[[nodiscard]] int frequency_point_size() const;
void set_frequency_point_size(int value);
[[nodiscard]] int power_point_size() const;
void set_power_point_size(int value);
[[nodiscard]] bool interpolate() const;
void set_interpolate(bool value);
[[nodiscard]] double attenuation_rate() const;
void set_attenuation_rate(double value);
[[nodiscard]] std::size_t history_count() const;
[[nodiscard]] std::size_t latest_spectrum_point_count() const;
[[nodiscard]] std::size_t rendered_cell_count() const;
void append_spectrum(std::span<const double> values);
void append_spectrum(std::pmr::vector<double>&& values);
template <class Values> void append_spectrum(const Values& values) {
append_spectrum(std::span<const double>(values.data(), values.size()));
}
class Builder {
public:
Builder(std::shared_ptr<Renderable> parent,
std::shared_ptr<Frequency_Axis> frequency_axis,
std::shared_ptr<Axis> power_axis);
Builder& set_frequency_range(Range value) { frequency_range_ = value; return *this; }
Builder& set_power_range(Range value) { power_range_ = value; return *this; }
Builder& set_frequency_bin_count(int value) { frequency_count_ = value; return *this; }
Builder& set_power_bin_count(int value) { power_count_ = value; return *this; }
Builder& set_interpolate_power_bins(bool value) { interpolate_ = value; return *this; }
Builder& set_decay_rate(double value) { attenuation_ = value; return *this; }
Builder& set_color_map(Color_Map value) { color_map_ = std::move(value); return *this; }
std::shared_ptr<Afterglow> build();
private:
std::shared_ptr<Renderable> parent_;
std::shared_ptr<Frequency_Axis> frequency_axis_;
std::shared_ptr<Axis> power_axis_;
Range frequency_range_{0.0, 10.0};
Range power_range_{0.0, 10.0};
int frequency_count_{};
int power_count_{};
bool interpolate_{true};
double attenuation_ = 0.2;
Color_Map color_map_;
};
protected:
void paint(detail::Painter& painter) override;
private:
struct State {
std::shared_ptr<Frequency_Axis> frequency_axis;
std::shared_ptr<Axis> power_axis;
Range frequency_range{0.0, 10.0};
Range power_range{0.0, 10.0};
int frequency_count{};
int power_count{};
bool interpolate{true};
double attenuation = 0.2;
Color_Map color_map;
std::deque<std::vector<double>> history;
};
[[nodiscard]] State state_snapshot() const;
mutable std::mutex mutex_;
State state_;
};
class LIB_DECL Sweep_Spectrum final : public Renderable {
public:
Sweep_Spectrum(Plot_Core& plot, std::shared_ptr<Axis> frequency_axis,
std::shared_ptr<Axis> power_axis);
void append_block(std::span<const double> values);
void append_block(std::pmr::vector<double>&& values);
template <class Values> void append_block(const Values& values) {
append_block(std::span<const double>(values.data(), values.size()));
}
[[nodiscard]] std::shared_ptr<Axis> frequency_axis() const;
[[nodiscard]] std::shared_ptr<Axis> power_axis() const;
[[nodiscard]] Range frequency_range() const;
void set_frequency_range(Range value);
[[nodiscard]] int bins_per_block() const;
void set_bins_per_block(int value);
[[nodiscard]] int block_count() const;
void set_block_count(int value);
[[nodiscard]] std::size_t stored_block_count() const;
[[nodiscard]] std::size_t stored_point_count() const;
[[nodiscard]] std::size_t rendered_point_count() const;
[[nodiscard]] Pen pen() const;
void set_pen(Pen value);
[[nodiscard]] Pen cur_frequency_pen() const;
void set_cur_frequency_pen(Pen value);
[[nodiscard]] bool visible_range_only() const;
void set_visible_range_only(bool value);
[[nodiscard]] Line_Interpolation_Mode interpolation_mode() const;
void set_interpolation_mode(Line_Interpolation_Mode value);
class Builder {
public:
Builder(std::shared_ptr<Renderable> parent, std::shared_ptr<Axis> frequency_axis,
std::shared_ptr<Axis> power_axis);
Builder& set_frequency_range(Range value) { frequency_range_ = value; return *this; }
Builder& set_bins_per_block(int value) { bins_ = value; return *this; }
Builder& set_block_num(int value) { blocks_ = value; return *this; }
Builder& set_pen(Pen value) { pen_ = value; return *this; }
Builder& set_current_frequency_pen(Pen value) { current_pen_ = value; return *this; }
Builder& set_visible_range_only(bool value) { visible_only_ = value; return *this; }
Builder& set_interpolation_mode(Line_Interpolation_Mode value) { interpolation_ = value; return *this; }
std::shared_ptr<Sweep_Spectrum> build();
private:
std::shared_ptr<Renderable> parent_;
std::shared_ptr<Axis> frequency_axis_;
std::shared_ptr<Axis> power_axis_;
Range frequency_range_{};
int bins_{};
int blocks_{};
Pen pen_{Color::yellow()};
Pen current_pen_{Color::red(), 2.0};
bool visible_only_{true};
Line_Interpolation_Mode interpolation_ = Line_Interpolation_Mode::Linear_Value;
};
protected:
void paint(detail::Painter& painter) override;
private:
struct State {
std::shared_ptr<Axis> frequency_axis;
std::shared_ptr<Axis> power_axis;
Range frequency_range{};
int bins{};
int blocks{};
Pen pen{Color::yellow()};
Pen current_pen{Color::red(), 2.0};
bool visible_only{true};
Line_Interpolation_Mode interpolation = Line_Interpolation_Mode::Linear_Value;
std::deque<std::vector<double>> data;
};
[[nodiscard]] State state_snapshot() const;
mutable std::mutex mutex_;
State state_;
};
class LIB_DECL Selection_Rectangle_Overlay final : public Renderable, public Event_Handler {
public:
Selection_Rectangle_Overlay(Plot_Core& plot, std::shared_ptr<Abs_Axis> horizontal_axis,
std::shared_ptr<Abs_Axis> vertical_axis);
void set_horizontal_axis(std::shared_ptr<Abs_Axis> axis);
void set_vertical_axis(std::shared_ptr<Abs_Axis> axis);
[[nodiscard]] Font label_font() const;
[[nodiscard]] Pen label_pen() const;
[[nodiscard]] Brush selection_brush() const;
[[nodiscard]] Pen selection_border_pen() const;
void set_label_font(Font value);
void set_label_pen(Pen value);
void set_selection_brush(Brush value);
void set_selection_border_pen(Pen value);
[[nodiscard]] std::vector<RectF> selected_regions() const;
void clear_selected_regions();
void handle_event(const Event& event) override;
class Builder {
public:
Builder(std::shared_ptr<Renderable> parent, std::shared_ptr<Abs_Axis> horizontal_axis,
std::shared_ptr<Abs_Axis> vertical_axis);
Builder& set_font(Font value) { font_ = value; return *this; }
Builder& set_font_pen(Pen value) { label_pen_ = value; return *this; }
Builder& set_rect_brush(Brush value) { brush_ = value; return *this; }
Builder& set_border_pen(Pen value) { border_ = value; return *this; }
std::shared_ptr<Selection_Rectangle_Overlay> build();
private:
std::shared_ptr<Renderable> parent_;
std::shared_ptr<Abs_Axis> horizontal_axis_;
std::shared_ptr<Abs_Axis> vertical_axis_;
Font font_;
Pen label_pen_{Color::white()};
Brush brush_{Color{0, 0, 255, 50}, Brush_Style::Solid};
Pen border_{Color::white(), 1.0, Line_Style::Dash};
};
protected:
void paint(detail::Painter& painter) override;
private:
mutable std::mutex mutex_;
std::shared_ptr<Abs_Axis> horizontal_axis_;
std::shared_ptr<Abs_Axis> vertical_axis_;
Font font_;
Pen label_pen_{Color::white()};
Brush brush_{Color{0, 0, 255, 50}, Brush_Style::Solid};
Pen border_{Color::white(), 1.0, Line_Style::Dash};
std::vector<RectF> regions_;
bool selecting_{};
PointF selection_start_{};
PointF selection_current_{};
};
enum class Constellation_Diagram_Type : std::uint8_t { Psk4 = 4, Psk8 = 8, Psk16 = 16 };
class LIB_DECL Constellation_Diagram final : public Renderable {
public:
Constellation_Diagram(Plot_Core& plot, std::shared_ptr<Axis> i_axis,
std::shared_ptr<Axis> q_axis);
void append_point(PointF point);
[[nodiscard]] std::shared_ptr<Axis> i_axis() const;
[[nodiscard]] std::shared_ptr<Axis> q_axis() const;
[[nodiscard]] Range i_range() const;
void set_i_range(Range value);
[[nodiscard]] Range q_range() const;
void set_q_range(Range value);
[[nodiscard]] Color point_color() const;
void set_point_color(Color value);
[[nodiscard]] Color anchor_color() const;
void set_anchor_color(Color value);
[[nodiscard]] int point_lifetime_ms() const;
void set_point_lifetime_ms(int value);
[[nodiscard]] std::size_t point_count() const;
void fit_square_to_axes();
class Builder {
public:
Builder(std::shared_ptr<Renderable> parent, std::shared_ptr<Axis> i_axis,
std::shared_ptr<Axis> q_axis);
Builder& set_i_range(Range value) { i_range_ = value; return *this; }
Builder& set_q_range(Range value) { q_range_ = value; return *this; }
Builder& set_point_color(Color value) { point_color_ = value; return *this; }
Builder& set_anchor_color(Color value) { anchor_color_ = value; return *this; }
Builder& set_point_lifetime_ms(int value) { lifetime_ = value; return *this; }
Builder& set_type(Constellation_Diagram_Type value) { type_ = value; return *this; }
Builder& set_phase_offset_radians(double value) { phase_ = value; return *this; }
std::shared_ptr<Constellation_Diagram> build();
private:
std::shared_ptr<Renderable> parent_;
std::shared_ptr<Axis> i_axis_;
std::shared_ptr<Axis> q_axis_;
Range i_range_{0.0, 100.0};
Range q_range_{0.0, 100.0};
Color point_color_ = Color::red();
Color anchor_color_ = Color::yellow();
int lifetime_ = 1000;
Constellation_Diagram_Type type_ = Constellation_Diagram_Type::Psk8;
double phase_{};
};
protected:
void paint(detail::Painter& painter) override;
private:
struct Timed_Point { PointF point; std::chrono::steady_clock::time_point time; };
struct State {
std::shared_ptr<Axis> i_axis;
std::shared_ptr<Axis> q_axis;
Range i_range{0.0, 100.0};
Range q_range{0.0, 100.0};
Color point_color = Color::red();
Color anchor_color = Color::yellow();
int lifetime_ms = 1000;
Constellation_Diagram_Type type = Constellation_Diagram_Type::Psk8;
double phase{};
std::deque<Timed_Point> points;
};
[[nodiscard]] State state_snapshot() const;
mutable std::mutex mutex_;
State state_;
};
} // namespace renderive