#pragma once #include "../axis/Axis.h" #include "Hover_Tooltip.h" #include #include #include #include #include namespace renderive { class LIB_DECL Spectrum final : public Renderable, public Event_Handler, public Hover_Tooltip_Mixin { public: Spectrum(Plot_Core& plot, std::shared_ptr frequency_axis, std::shared_ptr power_axis); [[nodiscard]] std::shared_ptr frequency_axis() const; void set_frequency_axis(std::shared_ptr value); [[nodiscard]] std::shared_ptr power_axis() const; void set_power_axis(std::shared_ptr 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 values); void update_samples(std::pmr::vector&& values); template void update_samples(const Values& values) { update_samples(std::span(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 parent, std::shared_ptr frequency_axis, std::shared_ptr 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 build(); private: std::shared_ptr parent_; std::shared_ptr frequency_axis_; std::shared_ptr 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; std::shared_ptr 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 samples; std::vector maxima; std::vector minima; std::vector 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 { public: Waterfall(Plot_Core& plot, std::shared_ptr frequency_axis, std::shared_ptr time_axis); void append_row(int tick, std::span values); void append_row(int tick, std::pmr::vector&& values); void append_row(Time_Of_Day time, std::span values); void append_row(Time_Of_Day time, std::pmr::vector&& values); template void append_row(Time_Of_Day time, const Values& values) { append_row(time, std::span(values.data(), values.size())); } [[nodiscard]] std::shared_ptr frequency_axis() const; [[nodiscard]] std::shared_ptr 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 parent, std::shared_ptr frequency_axis, std::shared_ptr 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 build(); private: std::shared_ptr parent_; std::shared_ptr frequency_axis_; std::shared_ptr 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 values; }; struct State { std::shared_ptr frequency_axis; std::shared_ptr 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 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, std::shared_ptr value_axis); void append_sample(int tick, double value); void append_sample(Time_Of_Day time, double value); [[nodiscard]] std::shared_ptr time_axis() const; [[nodiscard]] std::shared_ptr 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 parent, std::shared_ptr time_axis, std::shared_ptr value_axis); Builder& set_color(Color value) { pen_.color = value; return *this; } Builder& set_pen(Pen value) { pen_ = value; return *this; } std::shared_ptr build(); private: std::shared_ptr parent_; std::shared_ptr time_axis_; std::shared_ptr value_axis_; Pen pen_{Color::yellow()}; }; protected: void paint(detail::Painter& painter) override; private: mutable std::mutex mutex_; std::shared_ptr time_axis_; std::shared_ptr value_axis_; Pen pen_{Color::yellow()}; std::deque> samples_; }; class LIB_DECL Afterglow final : public Renderable { public: Afterglow(Plot_Core& plot, std::shared_ptr frequency_axis, std::shared_ptr power_axis); [[nodiscard]] std::shared_ptr frequency_axis() const; [[nodiscard]] std::shared_ptr 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 values); void append_spectrum(std::pmr::vector&& values); template void append_spectrum(const Values& values) { append_spectrum(std::span(values.data(), values.size())); } class Builder { public: Builder(std::shared_ptr parent, std::shared_ptr frequency_axis, std::shared_ptr 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 build(); private: std::shared_ptr parent_; std::shared_ptr frequency_axis_; std::shared_ptr 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; std::shared_ptr 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> 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 frequency_axis, std::shared_ptr power_axis); void append_block(std::span values); void append_block(std::pmr::vector&& values); template void append_block(const Values& values) { append_block(std::span(values.data(), values.size())); } [[nodiscard]] std::shared_ptr frequency_axis() const; [[nodiscard]] std::shared_ptr 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 parent, std::shared_ptr frequency_axis, std::shared_ptr 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 build(); private: std::shared_ptr parent_; std::shared_ptr frequency_axis_; std::shared_ptr 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 frequency_axis; std::shared_ptr 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> 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 horizontal_axis, std::shared_ptr vertical_axis); void set_horizontal_axis(std::shared_ptr axis); void set_vertical_axis(std::shared_ptr 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 selected_regions() const; void clear_selected_regions(); void handle_event(const Event& event) override; class Builder { public: Builder(std::shared_ptr parent, std::shared_ptr horizontal_axis, std::shared_ptr 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 build(); private: std::shared_ptr parent_; std::shared_ptr horizontal_axis_; std::shared_ptr 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 horizontal_axis_; std::shared_ptr 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 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 i_axis, std::shared_ptr q_axis); void append_point(PointF point); [[nodiscard]] std::shared_ptr i_axis() const; [[nodiscard]] std::shared_ptr 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 parent, std::shared_ptr i_axis, std::shared_ptr 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 build(); private: std::shared_ptr parent_; std::shared_ptr i_axis_; std::shared_ptr 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 i_axis; std::shared_ptr 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 points; }; [[nodiscard]] State state_snapshot() const; mutable std::mutex mutex_; State state_; }; } // namespace renderive