builder 和 运行时修改隔离开

This commit is contained in:
2026-08-13 11:25:38 +08:00
parent 9e598a0318
commit 4a48e62aea
57 changed files with 1512 additions and 2592 deletions
+265 -180
View File
@@ -6,12 +6,20 @@
#include <array>
#include <chrono>
#include <cstddef>
#include <functional>
#include <memory_resource>
#include <set>
#include <thread>
#include <tuple>
#include <utility>
#include <vector>
namespace renderive {
namespace {
template <class Scene, class Build>
decltype(auto) build_initial(Scene& scene, Build&& build) {
auto attach = scene.attach_builder();
return std::invoke(std::forward<Build>(build), attach);
}
template <class Axis_Type>
concept Legacy_Axis_Property_Api = requires(Axis_Type& axis) {
axis.x();
@@ -143,28 +151,31 @@ TEST(Renderive_Core2, KernelSceneRendersBusinessObjectsIntoBlend2DFrame) {
plot.activate_view();
const auto root = plot.root_renderable();
ASSERT_TRUE(root);
auto frequency_axis = Frequency_Axis::Builder(root, Orientation::Horizontal)
.set_x(32)
.set_y(150)
.set_pixel_length(270)
.set_coord_range({88.0, 108.0})
.build();
auto [frequency_axis, power_axis, spectrum] = build_initial(plot, [&](auto& attach) {
auto frequency = Frequency_Axis::Builder(root, Orientation::Horizontal, &attach)
.set_x(32)
.set_y(150)
.set_pixel_length(270)
.set_coord_range({88.0, 108.0})
.build();
auto power = Axis::Builder(root, Orientation::Vertical, &attach)
.set_x(32)
.set_y(8)
.set_pixel_length(142)
.set_coord_range({-120.0, 0.0})
.build();
auto value = Spectrum::Builder{&attach}
.set<&Spectrum::Properties::frequency_range>(Range{88.0, 108.0})
.set<&Spectrum::Properties::frequency_point_size>(64)
.set<&Spectrum::Properties::max_hold_visible>(true)
.build(root, frequency, power);
return std::tuple{frequency, power, value};
});
frequency_axis->set<&Axis_Base_Properties::locale>(Number_Locale{','});
frequency_axis->set<&Axis_Base_Properties::label_rotation_degrees>(15);
EXPECT_EQ(frequency_axis->tick_label(88.5), "88,5 Hz");
frequency_axis->set<&Axis_Properties::precision>(4);
EXPECT_EQ(frequency_axis->tick_label(1'234'567.0), "1,2346 MHz");
auto power_axis = Axis::Builder(root, Orientation::Vertical)
.set_x(32)
.set_y(8)
.set_pixel_length(142)
.set_coord_range({-120.0, 0.0})
.build();
auto spectrum = Spectrum::Builder{}
.set<&Spectrum::Properties::frequency_range>(Range{88.0, 108.0})
.set<&Spectrum::Properties::frequency_point_size>(64)
.set<&Spectrum::Properties::max_hold_visible>(true)
.build(root, frequency_axis, power_axis);
std::vector<double> samples(64);
for (std::size_t index = 0; index < samples.size(); ++index)
samples[index] = -100.0 + static_cast<double>(index % 24) * 3.0;
@@ -201,19 +212,52 @@ TEST(Renderive_Core2, KernelSceneRendersBusinessObjectsIntoBlend2DFrame) {
EXPECT_TRUE(wheel.is_accepted());
EXPECT_LT(frequency_axis->get<&Axis_Properties::coordinates>().size(), before_zoom.size());
EXPECT_TRUE(plot.render_frame());
plot.remove_renderable(spectrum);
plot.edit_renderables([root, frequency_axis, power_axis, spectrum](auto& editor) {
editor.set_parent(::Scene_Base::Relationship::display, frequency_axis, root);
editor.set_parent(::Scene_Base::Relationship::display, power_axis, root);
editor.clear_parents(::Scene_Base::Relationship::display, spectrum);
editor.clear_parents(::Scene_Base::Relationship::dependency, spectrum);
editor.detach(spectrum);
});
EXPECT_TRUE(plot.render_frame(true));
EXPECT_FALSE(plot.render_frame());
}
TEST(Renderive_Core2, StandaloneRenderableBuilderJoinsSceneOnlyInsideRuntimeEditor) {
Scene2D plot;
plot.init();
const auto root = plot.root_renderable();
const auto [frequency, power] = build_initial(plot, [&](auto& attach) {
return std::pair{
Frequency_Axis::Builder(root, Orientation::Horizontal, &attach).build(),
Axis::Builder(root, Orientation::Vertical, &attach).build()
};
});
const auto spectrum = Spectrum::Builder{}.build(root, frequency, power);
ASSERT_TRUE(spectrum);
EXPECT_FALSE(spectrum->attached());
plot.edit_renderables([root, frequency, power, spectrum](auto& editor) {
editor.attach(spectrum);
editor.add_parent(::Scene_Base::Relationship::display, spectrum, root);
editor.add_parent(::Scene_Base::Relationship::dependency, spectrum, root);
editor.add_parent(::Scene_Base::Relationship::dependency, spectrum, frequency);
editor.add_parent(::Scene_Base::Relationship::dependency, spectrum, power);
editor.add_parent(::Scene_Base::Relationship::display, frequency, spectrum);
editor.add_parent(::Scene_Base::Relationship::display, power, spectrum);
});
EXPECT_TRUE(plot.render_frame(true));
EXPECT_TRUE(spectrum->attached());
}
TEST(Renderive_Core2, TimeAxisUsesOneFontStateAndFormatsConfiguredLabels) {
Scene2D plot;
plot.init();
const auto root = plot.root_renderable();
auto axis = Time_Axis::Builder(root, Orientation::Horizontal)
.set_time_format("hh-mm-ss.zzz")
.set_font(Font{18.0, 700, true})
.set_tick_label_spacing_px(17)
.build();
auto axis = build_initial(plot, [&](auto& attach) {
return Time_Axis::Builder(root, Orientation::Horizontal, &attach)
.set_time_format("hh-mm-ss.zzz")
.set_font(Font{18.0, 700, true})
.set_tick_label_spacing_px(17)
.build();
});
ASSERT_TRUE(axis);
const int tick = axis->append_time(Time_Of_Day{3'723'045});
EXPECT_EQ(axis->tick_label(tick), "01-02-03.045");
@@ -285,24 +329,25 @@ TEST(Renderive_Core2, RetainedAxisAndTimeAxisApisRoundTripWithoutWebAdapters) {
plot.init();
const auto root = plot.root_renderable();
ASSERT_TRUE(root);
const auto axis = Axis::Builder(root, Orientation::Vertical)
.set_x(31)
.set_y(17)
.set_pixel_length(240)
.set_tick_length(13)
.set_sub_tick_length(7)
.set_color({10, 20, 30, 255})
.set_unit_text("dB")
.set_unit_text_font({15.0, 650, true})
.set_unit_text_pen({Color{40, 50, 60, 255}, 2.0})
.set_unit_text_background_brush(
{Color{3, 4, 5, 255}, Brush_Style::Solid})
.set_label_rotation_degrees(27)
.set_coord_range({-120.0, -20.0})
.set_label_precision(4)
.set_use_wheel(true)
.set_use_drag(true)
.build();
const auto axis = build_initial(plot, [&](auto& attach) {
return Axis::Builder(root, Orientation::Vertical, &attach)
.set_x(31)
.set_y(17)
.set_pixel_length(240)
.set_tick_length(13)
.set_sub_tick_length(7)
.set_color({10, 20, 30, 255})
.set_unit_text("dB")
.set_unit_text_font({15.0, 650, true})
.set_unit_text_pen({Color{40, 50, 60, 255}, 2.0})
.set_unit_text_background_brush({Color{3, 4, 5, 255}, Brush_Style::Solid})
.set_label_rotation_degrees(27)
.set_coord_range({-120.0, -20.0})
.set_label_precision(4)
.set_use_wheel(true)
.set_use_drag(true)
.build();
});
ASSERT_TRUE(axis);
EXPECT_EQ(axis->get<&Axis_Base_Properties::x>(), 31);
EXPECT_EQ(axis->get<&Axis_Base_Properties::y>(), 17);
@@ -333,16 +378,18 @@ TEST(Renderive_Core2, RetainedAxisAndTimeAxisApisRoundTripWithoutWebAdapters) {
EXPECT_GT(static_cast<int>(numeric_transform.pixel_length) + 1, 0);
EXPECT_GT(axis->tick_step(numeric_transform.coordinate_range), 0.0);
EXPECT_GE(axis->sub_tick_count(axis->tick_step(numeric_transform.coordinate_range)), 0);
const auto time_axis = Time_Axis::Builder(root, Orientation::Horizontal)
.set_x(12)
.set_y(280)
.set_pixel_length(300)
.set_visible_time_point_count(32)
.set_tick_label_spacing_px(19)
.set_time_format("hh:mm:ss.zzz")
.set_font({16.0, 700, true})
.set_newest_at_axis_start(true)
.build();
const auto time_axis = build_initial(plot, [&](auto& attach) {
return Time_Axis::Builder(root, Orientation::Horizontal, &attach)
.set_x(12)
.set_y(280)
.set_pixel_length(300)
.set_visible_time_point_count(32)
.set_tick_label_spacing_px(19)
.set_time_format("hh:mm:ss.zzz")
.set_font({16.0, 700, true})
.set_newest_at_axis_start(true)
.build();
});
ASSERT_TRUE(time_axis);
const int first = time_axis->append_time({3'723'004});
const int second = time_axis->append_time({3'724'005});
@@ -363,25 +410,28 @@ TEST(Renderive_Core2, RetainedSpectrumApisRoundTripAndMarkersRemainObservable) {
plot.set_viewport_size({360, 240});
plot.activate_view();
const auto root = plot.root_renderable();
const auto frequency = Frequency_Axis::Builder(root, Orientation::Horizontal)
.set_x(30).set_y(210).set_pixel_length(300)
.set_coord_range({90.0, 110.0}).build();
const auto power = Axis::Builder(root, Orientation::Vertical)
.set_x(30).set_y(20).set_pixel_length(190)
.set_coord_range({-20.0, -120.0}).build();
auto spectrum = Spectrum::Builder{}
.set<&Spectrum::Properties::frequency_range>(Range{90.0, 110.0})
.set<&Spectrum::Properties::frequency_point_size>(4)
.set<&Spectrum::Properties::center_frequency>(100.0)
.set<&Spectrum::Properties::sweep_frequency_range>(Range{96.0, 104.0})
.set<&Spectrum::Properties::max_hold_visible>(true)
.set<&Spectrum::Properties::min_hold_visible>(true)
.set<&Spectrum::Properties::max_marker_visible>(true)
.set<&Spectrum::Properties::use_min_marker>(true)
.set<&Spectrum::Properties::sweep_region_visible>(true)
.set<&Spectrum::Properties::visible_range_only>(false)
.set<&Spectrum::Properties::interpolation_mode>(Line_Interpolation_Mode::Cubic_Value)
.build(root, frequency, power);
auto [frequency, power, spectrum] = build_initial(plot, [&](auto& attach) {
auto frequency_axis = Frequency_Axis::Builder(root, Orientation::Horizontal, &attach)
.set_x(30).set_y(210).set_pixel_length(300)
.set_coord_range({90.0, 110.0}).build();
auto power_axis = Axis::Builder(root, Orientation::Vertical, &attach)
.set_x(30).set_y(20).set_pixel_length(190)
.set_coord_range({-20.0, -120.0}).build();
auto value = Spectrum::Builder{&attach}
.set<&Spectrum::Properties::frequency_range>(Range{90.0, 110.0})
.set<&Spectrum::Properties::frequency_point_size>(4)
.set<&Spectrum::Properties::center_frequency>(100.0)
.set<&Spectrum::Properties::sweep_frequency_range>(Range{96.0, 104.0})
.set<&Spectrum::Properties::max_hold_visible>(true)
.set<&Spectrum::Properties::min_hold_visible>(true)
.set<&Spectrum::Properties::max_marker_visible>(true)
.set<&Spectrum::Properties::use_min_marker>(true)
.set<&Spectrum::Properties::sweep_region_visible>(true)
.set<&Spectrum::Properties::visible_range_only>(false)
.set<&Spectrum::Properties::interpolation_mode>(Line_Interpolation_Mode::Cubic_Value)
.build(root, frequency_axis, power_axis);
return std::tuple{frequency_axis, power_axis, value};
});
ASSERT_TRUE(spectrum);
spectrum->set<&Spectrum::Properties::max_brush>(Brush{Color{1, 2, 3, 80}, Brush_Style::Solid});
spectrum->set<&Spectrum::Properties::current_brush>(Brush{Color{4, 5, 6, 90}, Brush_Style::Solid});
@@ -441,22 +491,25 @@ TEST(Renderive_Core2, RetainedHeatmapSweepAndTraceApisPreserveDataShapes) {
plot.set_viewport_size({420, 280});
plot.activate_view();
const auto root = plot.root_renderable();
const auto frequency = Frequency_Axis::Builder(root, Orientation::Horizontal)
.set_x(40).set_y(250).set_pixel_length(340)
.set_coord_range({0.0, 4.0}).build();
const auto power = Axis::Builder(root, Orientation::Vertical)
.set_x(40).set_y(20).set_pixel_length(230)
.set_coord_range({0.0, -120.0}).build();
const auto time = Time_Axis::Builder(root, Orientation::Vertical)
.set_x(40).set_y(20).set_pixel_length(230)
.set_visible_time_point_count(8).build();
auto waterfall = Waterfall::Builder{}
.set<&Waterfall::Properties::frequency_range>(Range{0.0, 4.0})
.set<&Waterfall::Properties::power_range>(Range{-120.0, 0.0})
.set<&Waterfall::Properties::frequency_bin_count>(4)
.set<&Waterfall::Properties::visible_range_only>(false)
.set<&Waterfall::Properties::interpolation_mode>(Image_Interpolation_Mode::Bicubic)
.build(root, frequency, time);
auto [frequency, power, time, waterfall] = build_initial(plot, [&](auto& attach) {
auto frequency_axis = Frequency_Axis::Builder(root, Orientation::Horizontal, &attach)
.set_x(40).set_y(250).set_pixel_length(340)
.set_coord_range({0.0, 4.0}).build();
auto power_axis = Axis::Builder(root, Orientation::Vertical, &attach)
.set_x(40).set_y(20).set_pixel_length(230)
.set_coord_range({0.0, -120.0}).build();
auto time_axis = Time_Axis::Builder(root, Orientation::Vertical, &attach)
.set_x(40).set_y(20).set_pixel_length(230)
.set_visible_time_point_count(8).build();
auto value = Waterfall::Builder{&attach}
.set<&Waterfall::Properties::frequency_range>(Range{0.0, 4.0})
.set<&Waterfall::Properties::power_range>(Range{-120.0, 0.0})
.set<&Waterfall::Properties::frequency_bin_count>(4)
.set<&Waterfall::Properties::visible_range_only>(false)
.set<&Waterfall::Properties::interpolation_mode>(Image_Interpolation_Mode::Bicubic)
.build(root, frequency_axis, time_axis);
return std::tuple{frequency_axis, power_axis, time_axis, value};
});
ASSERT_TRUE(waterfall);
EXPECT_EQ(waterfall->get<&Waterfall::Properties::frequency_range>(), (Range{0.0, 4.0}));
EXPECT_EQ(waterfall->get<&Waterfall::Properties::power_range>(), (Range{-120.0, 0.0}));
@@ -471,14 +524,16 @@ TEST(Renderive_Core2, RetainedHeatmapSweepAndTraceApisPreserveDataShapes) {
EXPECT_EQ(waterfall->row_count(), 2U);
EXPECT_EQ(waterfall->stored_point_count(), 8U);
EXPECT_EQ(waterfall->rendered_cell_count(), 8U);
auto afterglow = Afterglow::Builder{}
.set<&Afterglow::Properties::frequency_range>(Range{0.0, 4.0})
.set<&Afterglow::Properties::power_range>(Range{-120.0, 0.0})
.set<&Afterglow::Properties::frequency_point_size>(4)
.set<&Afterglow::Properties::power_point_size>(8)
.set<&Afterglow::Properties::interpolate>(false)
.set<&Afterglow::Properties::attenuation_rate>(0.35)
.build(root, frequency, power);
auto afterglow = build_initial(plot, [&](auto& attach) {
return Afterglow::Builder{&attach}
.set<&Afterglow::Properties::frequency_range>(Range{0.0, 4.0})
.set<&Afterglow::Properties::power_range>(Range{-120.0, 0.0})
.set<&Afterglow::Properties::frequency_point_size>(4)
.set<&Afterglow::Properties::power_point_size>(8)
.set<&Afterglow::Properties::interpolate>(false)
.set<&Afterglow::Properties::attenuation_rate>(0.35)
.build(root, frequency, power);
});
ASSERT_TRUE(afterglow);
EXPECT_EQ(afterglow->get<&Afterglow::Properties::frequency_range>(), (Range{0.0, 4.0}));
EXPECT_EQ(afterglow->get<&Afterglow::Properties::power_range>(), (Range{-120.0, 0.0}));
@@ -495,15 +550,17 @@ TEST(Renderive_Core2, RetainedHeatmapSweepAndTraceApisPreserveDataShapes) {
EXPECT_EQ(afterglow->rendered_cell_count(), 32U);
afterglow->set<&Afterglow::Properties::attenuation_rate>(2.0);
EXPECT_DOUBLE_EQ(afterglow->get<&Afterglow::Properties::attenuation_rate>(), 1.0);
auto sweep = Sweep_Spectrum::Builder{}
.set<&Sweep_Spectrum::Properties::frequency_range>(Range{0.0, 8.0})
.set<&Sweep_Spectrum::Properties::bins_per_block>(4)
.set<&Sweep_Spectrum::Properties::block_count>(2)
.set<&Sweep_Spectrum::Properties::pen>(Pen{Color{1, 120, 220, 255}, 2.0})
.set<&Sweep_Spectrum::Properties::current_frequency_pen>(Pen{Color{240, 80, 20, 255}, 3.0})
.set<&Sweep_Spectrum::Properties::visible_range_only>(false)
.set<&Sweep_Spectrum::Properties::interpolation_mode>(Line_Interpolation_Mode::Step_Right)
.build(root, frequency, power);
auto sweep = build_initial(plot, [&](auto& attach) {
return Sweep_Spectrum::Builder{&attach}
.set<&Sweep_Spectrum::Properties::frequency_range>(Range{0.0, 8.0})
.set<&Sweep_Spectrum::Properties::bins_per_block>(4)
.set<&Sweep_Spectrum::Properties::block_count>(2)
.set<&Sweep_Spectrum::Properties::pen>(Pen{Color{1, 120, 220, 255}, 2.0})
.set<&Sweep_Spectrum::Properties::current_frequency_pen>(Pen{Color{240, 80, 20, 255}, 3.0})
.set<&Sweep_Spectrum::Properties::visible_range_only>(false)
.set<&Sweep_Spectrum::Properties::interpolation_mode>(Line_Interpolation_Mode::Step_Right)
.build(root, frequency, power);
});
ASSERT_TRUE(sweep);
EXPECT_EQ(sweep->get<&Sweep_Spectrum::Properties::frequency_range>(), (Range{0.0, 8.0}));
EXPECT_EQ(sweep->get<&Sweep_Spectrum::Properties::bins_per_block>(), 4);
@@ -518,9 +575,11 @@ TEST(Renderive_Core2, RetainedHeatmapSweepAndTraceApisPreserveDataShapes) {
EXPECT_EQ(sweep->stored_block_count(), 2U);
EXPECT_EQ(sweep->stored_point_count(), 8U);
EXPECT_GT(sweep->rendered_point_count(), 0U);
auto trace = Frequency_Trace::Builder{}
.set<&Frequency_Trace::Properties::pen>(Pen{Color{120, 240, 80, 255}, 2.0})
.build(root, time, power);
auto trace = build_initial(plot, [&](auto& attach) {
return Frequency_Trace::Builder{&attach}
.set<&Frequency_Trace::Properties::pen>(Pen{Color{120, 240, 80, 255}, 2.0})
.build(root, time, power);
});
ASSERT_TRUE(trace);
trace->append_sample(Time_Of_Day{3000}, -80.0);
trace->append_sample(Time_Of_Day{4000}, -70.0);
@@ -534,18 +593,21 @@ TEST(Renderive_Core2, RetainedSelectionAndConstellationApisDriveInteractionAndLa
plot.set_viewport_size({360, 260});
plot.activate_view();
const auto root = plot.root_renderable();
const auto horizontal = Axis::Builder(root, Orientation::Horizontal)
.set_x(30).set_y(230).set_pixel_length(300)
.set_coord_range({-3.0, 3.0}).build();
const auto vertical = Axis::Builder(root, Orientation::Vertical)
.set_x(30).set_y(20).set_pixel_length(210)
.set_coord_range({3.0, -3.0}).build();
auto selection = Selection_Rectangle_Overlay::Builder{}
.set<&Selection_Rectangle_Overlay::Properties::label_font>(Font{14.0, 600, true})
.set<&Selection_Rectangle_Overlay::Properties::label_pen>(Pen{Color{20, 220, 180, 255}, 2.0})
.set<&Selection_Rectangle_Overlay::Properties::selection_brush>(Brush{Color{20, 80, 220, 60}, Brush_Style::Solid})
.set<&Selection_Rectangle_Overlay::Properties::selection_border_pen>(Pen{Color{240, 200, 60, 255}, 2.0, Line_Style::Dash})
.build(root, horizontal, vertical);
auto [horizontal, vertical, selection] = build_initial(plot, [&](auto& attach) {
auto horizontal_axis = Axis::Builder(root, Orientation::Horizontal, &attach)
.set_x(30).set_y(230).set_pixel_length(300)
.set_coord_range({-3.0, 3.0}).build();
auto vertical_axis = Axis::Builder(root, Orientation::Vertical, &attach)
.set_x(30).set_y(20).set_pixel_length(210)
.set_coord_range({3.0, -3.0}).build();
auto value = Selection_Rectangle_Overlay::Builder{&attach}
.set<&Selection_Rectangle_Overlay::Properties::label_font>(Font{14.0, 600, true})
.set<&Selection_Rectangle_Overlay::Properties::label_pen>(Pen{Color{20, 220, 180, 255}, 2.0})
.set<&Selection_Rectangle_Overlay::Properties::selection_brush>(Brush{Color{20, 80, 220, 60}, Brush_Style::Solid})
.set<&Selection_Rectangle_Overlay::Properties::selection_border_pen>(Pen{Color{240, 200, 60, 255}, 2.0, Line_Style::Dash})
.build(root, horizontal_axis, vertical_axis);
return std::tuple{horizontal_axis, vertical_axis, value};
});
ASSERT_TRUE(selection);
EXPECT_EQ(selection->get<&Selection_Rectangle_Overlay::Properties::label_font>(), (Font{14.0, 600, true}));
EXPECT_EQ(selection->get<&Selection_Rectangle_Overlay::Properties::label_pen>(), (Pen{Color{20, 220, 180, 255}, 2.0}));
@@ -571,7 +633,8 @@ TEST(Renderive_Core2, RetainedSelectionAndConstellationApisDriveInteractionAndLa
EXPECT_FALSE(selection->selected_regions().front().empty());
selection->clear_selected_regions();
EXPECT_TRUE(selection->selected_regions().empty());
auto constellation = Constellation_Diagram::Builder{}
auto constellation = build_initial(plot, [&](auto& attach) {
return Constellation_Diagram::Builder{&attach}
.set<&Constellation_Diagram::Properties::i_range>(Range{-2.0, 2.0})
.set<&Constellation_Diagram::Properties::q_range>(Range{-3.0, 3.0})
.set<&Constellation_Diagram::Properties::point_color>(Color{80, 220, 255, 255})
@@ -579,7 +642,8 @@ TEST(Renderive_Core2, RetainedSelectionAndConstellationApisDriveInteractionAndLa
.set<&Constellation_Diagram::Properties::point_lifetime_ms>(2000)
.set<&Constellation_Diagram::Properties::type>(Constellation_Diagram_Type::Psk16)
.set<&Constellation_Diagram::Properties::phase_offset_radians>(0.25)
.build(root, horizontal, vertical);
.build(root, horizontal, vertical);
});
ASSERT_TRUE(constellation);
EXPECT_EQ(constellation->get<&Constellation_Diagram::Properties::i_range>(), (Range{-2.0, 2.0}));
EXPECT_EQ(constellation->get<&Constellation_Diagram::Properties::q_range>(), (Range{-3.0, 3.0}));
@@ -598,11 +662,14 @@ TEST(Renderive_Core2, PlottablePropertiesPublishOnlyAtFrameBoundary) {
Scene2D plot;
plot.init();
const auto root = plot.root_renderable();
const auto frequency = Frequency_Axis::Builder(root, Orientation::Horizontal).build();
const auto power = Axis::Builder(root, Orientation::Vertical).build();
const auto spectrum = Spectrum::Builder{}.build(root, frequency, power);
const auto [frequency, power, spectrum] = build_initial(plot, [&](auto& attach) {
auto frequency_axis = Frequency_Axis::Builder(root, Orientation::Horizontal, &attach).build();
auto power_axis = Axis::Builder(root, Orientation::Vertical, &attach).build();
auto value = Spectrum::Builder{&attach}.build(root, frequency_axis, power_axis);
return std::tuple{frequency_axis, power_axis, value};
});
ASSERT_TRUE(spectrum);
const auto state = std::dynamic_pointer_cast<::State_Strategy_Base>(spectrum);
const auto state = renderive_dynamic_owner_cast<::State_Strategy_Base>(spectrum);
ASSERT_TRUE(state);
EXPECT_EQ(state->state_revision(), 0U);
spectrum->set<&Spectrum::Properties::frequency_point_size>(128);
@@ -616,9 +683,12 @@ TEST(Renderive_Core2, EveryStatefulRenderableOwnsItsStateObserver) {
Scene2D plot;
plot.init();
const auto root = plot.root_renderable();
const auto frequency = Frequency_Axis::Builder(root, Orientation::Horizontal).build();
const auto power = Axis::Builder(root, Orientation::Vertical).build();
const auto spectrum = Spectrum::Builder{}.build(root, frequency, power);
const auto [frequency, power, spectrum] = build_initial(plot, [&](auto& attach) {
auto frequency_axis = Frequency_Axis::Builder(root, Orientation::Horizontal, &attach).build();
auto power_axis = Axis::Builder(root, Orientation::Vertical, &attach).build();
auto value = Spectrum::Builder{&attach}.build(root, frequency_axis, power_axis);
return std::tuple{frequency_axis, power_axis, value};
});
ASSERT_TRUE(frequency);
ASSERT_TRUE(power);
ASSERT_TRUE(spectrum);
@@ -660,10 +730,15 @@ TEST(Renderive_Core2, PlottableDataUpdatesReachKernelRealTimeDataStrategy) {
Scene2D plot;
plot.init();
const auto root = plot.root_renderable();
const auto frequency = Frequency_Axis::Builder(root, Orientation::Horizontal).build();
const auto power = Axis::Builder(root, Orientation::Vertical).build();
const auto spectrum = Spectrum::Builder{}.build(root, frequency, power);
const auto afterglow = Afterglow::Builder{}.build(root, frequency, power);
const auto [frequency, power, spectrum] = build_initial(plot, [&](auto& attach) {
auto frequency_axis = Frequency_Axis::Builder(root, Orientation::Horizontal, &attach).build();
auto power_axis = Axis::Builder(root, Orientation::Vertical, &attach).build();
auto value = Spectrum::Builder{&attach}.build(root, frequency_axis, power_axis);
return std::tuple{frequency_axis, power_axis, value};
});
const auto afterglow = build_initial(plot, [&](auto& attach) {
return Afterglow::Builder{&attach}.build(root, frequency, power);
});
ASSERT_TRUE(spectrum);
ASSERT_TRUE(afterglow);
const auto before = plot.frame_observer_snapshot().observation_count;
@@ -726,32 +801,32 @@ TEST(Renderive_Core2, PartitionedPlotsBuildPropertyDrivenRenderGraphs) {
plot.init();
plot.set_viewport_size({320, 180});
const auto root = plot.root_renderable();
const auto frequency = Frequency_Axis::Builder(root, Orientation::Horizontal)
.set_pixel_length(320)
.set_coord_range({0.0, 10.0})
.build();
const auto power = Axis::Builder(root, Orientation::Vertical)
.set_pixel_length(180)
.set_coord_range({-120.0, 0.0})
.build();
const auto time = Time_Axis::Builder(root, Orientation::Vertical)
.set_pixel_length(180)
.build();
const auto spectrum = Spectrum::Builder{}
.set<&Spectrum::Properties::partition_mode>(
Render_Partition_Mode::Fixed)
.set<&Spectrum::Properties::partition_count>(4)
.build(root, frequency, power);
const auto waterfall = Waterfall::Builder{}
.set<&Waterfall::Properties::partition_mode>(
Render_Partition_Mode::Fixed)
.set<&Waterfall::Properties::partition_count>(4)
.build(root, frequency, time);
const auto afterglow = Afterglow::Builder{}
.set<&Afterglow::Properties::partition_mode>(
Render_Partition_Mode::Fixed)
.set<&Afterglow::Properties::partition_count>(4)
.build(root, frequency, power);
const auto [frequency, power, time, spectrum, waterfall, afterglow] = build_initial(plot, [&](auto& attach) {
auto frequency_axis = Frequency_Axis::Builder(root, Orientation::Horizontal, &attach)
.set_pixel_length(320)
.set_coord_range({0.0, 10.0})
.build();
auto power_axis = Axis::Builder(root, Orientation::Vertical, &attach)
.set_pixel_length(180)
.set_coord_range({-120.0, 0.0})
.build();
auto time_axis = Time_Axis::Builder(root, Orientation::Vertical, &attach)
.set_pixel_length(180)
.build();
auto spectrum_value = Spectrum::Builder{&attach}
.set<&Spectrum::Properties::partition_mode>(Render_Partition_Mode::Fixed)
.set<&Spectrum::Properties::partition_count>(4)
.build(root, frequency_axis, power_axis);
auto waterfall_value = Waterfall::Builder{&attach}
.set<&Waterfall::Properties::partition_mode>(Render_Partition_Mode::Fixed)
.set<&Waterfall::Properties::partition_count>(4)
.build(root, frequency_axis, time_axis);
auto afterglow_value = Afterglow::Builder{&attach}
.set<&Afterglow::Properties::partition_mode>(Render_Partition_Mode::Fixed)
.set<&Afterglow::Properties::partition_count>(4)
.build(root, frequency_axis, power_axis);
return std::tuple{frequency_axis, power_axis, time_axis, spectrum_value, waterfall_value, afterglow_value};
});
std::array<double, 1024> samples{};
spectrum->update_samples(samples);
waterfall->append_row(0, samples);
@@ -841,20 +916,21 @@ TEST(Renderive_Core2, DynamicWaterfallCaptureStressPreservesPlansSlotsAndExactSe
plot.init();
plot.set_viewport_size({640, 360});
const auto root = plot.root_renderable();
const auto frequency = Frequency_Axis::Builder(root, Orientation::Horizontal)
.set_pixel_length(640)
.set_coord_range({0.0, 32'767.0})
.build();
const auto time = Time_Axis::Builder(root, Orientation::Vertical)
.set_pixel_length(360)
.build();
const auto waterfall = Waterfall::Builder{}
.set<&Waterfall::Properties::partition_mode>(
Render_Partition_Mode::Fixed)
.set<&Waterfall::Properties::partition_count>(64)
.set<&Waterfall::Properties::frequency_range>(
Range{0.0, 32'767.0})
.build(root, frequency, time);
const auto [frequency, time, waterfall] = build_initial(plot, [&](auto& attach) {
auto frequency_axis = Frequency_Axis::Builder(root, Orientation::Horizontal, &attach)
.set_pixel_length(640)
.set_coord_range({0.0, 32'767.0})
.build();
auto time_axis = Time_Axis::Builder(root, Orientation::Vertical, &attach)
.set_pixel_length(360)
.build();
auto value = Waterfall::Builder{&attach}
.set<&Waterfall::Properties::partition_mode>(Render_Partition_Mode::Fixed)
.set<&Waterfall::Properties::partition_count>(64)
.set<&Waterfall::Properties::frequency_range>(Range{0.0, 32'767.0})
.build(root, frequency_axis, time_axis);
return std::tuple{frequency_axis, time_axis, value};
});
std::array<double, 32'768> samples{};
for (std::size_t index = 0; index < samples.size(); ++index)
samples[index] = static_cast<double>(index % 256);
@@ -899,9 +975,12 @@ TEST(Renderive_Core2, PaintOnlyStyleChangesPreservePrepareCache) {
plot.init();
plot.set_viewport_size({320, 180});
const auto root = plot.root_renderable();
const auto frequency = Frequency_Axis::Builder(root, Orientation::Horizontal).build();
const auto power = Axis::Builder(root, Orientation::Vertical).build();
const auto spectrum = Spectrum::Builder{}.build(root, frequency, power);
const auto [frequency, power, spectrum] = build_initial(plot, [&](auto& attach) {
auto frequency_axis = Frequency_Axis::Builder(root, Orientation::Horizontal, &attach).build();
auto power_axis = Axis::Builder(root, Orientation::Vertical, &attach).build();
auto value = Spectrum::Builder{&attach}.build(root, frequency_axis, power_axis);
return std::tuple{frequency_axis, power_axis, value};
});
const std::array samples{-80.0, -70.0, -60.0, -50.0};
spectrum->update_samples(samples);
ASSERT_TRUE(plot.render_frame(true));
@@ -946,9 +1025,12 @@ TEST(Renderive_Core2, PlottableAxesAreDataDependenciesAndPaintOverlays) {
Scene2D plot;
plot.init();
const auto root = plot.root_renderable();
const auto frequency = Frequency_Axis::Builder(root, Orientation::Horizontal).build();
const auto power = Axis::Builder(root, Orientation::Vertical).build();
const auto spectrum = Spectrum::Builder{}.build(root, frequency, power);
const auto [frequency, power, spectrum] = build_initial(plot, [&](auto& attach) {
auto frequency_axis = Frequency_Axis::Builder(root, Orientation::Horizontal, &attach).build();
auto power_axis = Axis::Builder(root, Orientation::Vertical, &attach).build();
auto value = Spectrum::Builder{&attach}.build(root, frequency_axis, power_axis);
return std::tuple{frequency_axis, power_axis, value};
});
ASSERT_TRUE(spectrum);
const auto topology = spectrum->scene().topology_snapshot();
const auto has_relationship = [](const auto& relationships, const auto* child, const auto* parent) {
@@ -980,9 +1062,12 @@ TEST(Renderive_Core2, InteractionOverlayPaintsAboveItsAxes) {
Scene2D plot;
plot.init();
const auto root = plot.root_renderable();
const auto horizontal = Axis::Builder(root, Orientation::Horizontal).build();
const auto vertical = Axis::Builder(root, Orientation::Vertical).build();
const auto selection = Selection_Rectangle_Overlay::Builder{}.build(root, horizontal, vertical);
const auto [horizontal, vertical, selection] = build_initial(plot, [&](auto& attach) {
auto horizontal_axis = Axis::Builder(root, Orientation::Horizontal, &attach).build();
auto vertical_axis = Axis::Builder(root, Orientation::Vertical, &attach).build();
auto value = Selection_Rectangle_Overlay::Builder{&attach}.build(root, horizontal_axis, vertical_axis);
return std::tuple{horizontal_axis, vertical_axis, value};
});
ASSERT_TRUE(selection);
const auto paint_order = selection->scene().paint_order_snapshot();
const auto position = [&paint_order](const auto* target) {