2D移植完成
This commit is contained in:
@@ -1,282 +1,129 @@
|
||||
#include <render_2D/plottable/Plottables.hpp>
|
||||
#include <render_2D/base/Frame_2D.hpp>
|
||||
#include <render_2D/scene/Render_Scene_2D.hpp>
|
||||
#include <render_2D/module/plottable/Plottables.hpp>
|
||||
#include <gtest/gtest.h>
|
||||
#include <array>
|
||||
|
||||
#include <chrono>
|
||||
namespace {
|
||||
using namespace aethera;
|
||||
using namespace aethera::render_2d;
|
||||
|
||||
template <typename Object, typename... Args>
|
||||
std::unique_ptr<Object> build_object(Args&&... args) {
|
||||
typename Object::template Builder<Object> builder(std::forward<Args>(args)...);
|
||||
auto result = builder.build();
|
||||
if (!result) std::terminate();
|
||||
return std::move(result).value();
|
||||
}
|
||||
|
||||
template <typename Scene, typename... Renderables>
|
||||
std::unique_ptr<Scene> build_scene(Renderables*... renderables) {
|
||||
typename Scene::template Builder<Scene> builder;
|
||||
(builder.add_renderable(not_null{renderables}), ...);
|
||||
auto result = builder.build();
|
||||
if (!result) std::terminate();
|
||||
return std::move(result).value();
|
||||
}
|
||||
|
||||
template <typename Axis>
|
||||
void configure_axis(Axis* axis, Axis_Orientation orientation, Point_F position, Axis_Pixel_Length length, Size canvas) {
|
||||
axis->template set<&Abs_Axis::Prop::orientation>(orientation);
|
||||
axis->template set<&Abs_Axis::Prop::position>(position);
|
||||
axis->template set<&Abs_Axis::Prop::pixel_length>(length);
|
||||
}
|
||||
template <typename Scene>
|
||||
void render_once(Scene* scene) {
|
||||
static std::uint64_t sequence{1};
|
||||
Frame_2D frame{Frame_Identity{sequence++, 0}};
|
||||
EXPECT_TRUE(scene->render(
|
||||
&frame, [](not_null<Frame_2D*>) {}).has_value());
|
||||
}
|
||||
std::unique_ptr<Axis> make_axis(Axis_Orientation orientation, Axis_Range range) {
|
||||
typename Axis::Builder builder;
|
||||
builder
|
||||
.set<Prop_Tag>(&Abs_Axis::Prop::position, Point_F{10.0, 90.0})
|
||||
.set<Prop_Tag>(&Abs_Axis::Prop::pixel_length, orientation == Axis_Orientation::horizontal ? 100.0 : -80.0)
|
||||
.set<Prop_Tag>(&Abs_Axis::Prop::orientation, orientation);
|
||||
if constexpr (std::derived_from<Axis, Numeric_Axis>) builder.template set<Prop_Tag>(&Numeric_Axis::Prop::coordinate_range, range);
|
||||
auto axis = builder.build();
|
||||
aethera::detail::model_private(*axis).advance();
|
||||
return axis;
|
||||
}
|
||||
|
||||
TEST(plottable_migration, curve_plots_share_partitioned_rendering) {
|
||||
using Scene = Render_Scene_2D;
|
||||
using Frequency = Frequency_Axis;
|
||||
using Numeric = Numeric_Axis;
|
||||
using Time = Time_Axis;
|
||||
using Trace = Frequency_Trace;
|
||||
using Sweep = Sweep_Spectrum;
|
||||
initialize_runtime({.workers = 2});
|
||||
const Size canvas{160, 120};
|
||||
auto frequency = build_object<Frequency>();
|
||||
auto power = build_object<Numeric>();
|
||||
auto time = build_object<Time>();
|
||||
auto value = build_object<Numeric>();
|
||||
configure_axis(frequency.get(), Axis_Orientation::horizontal, {20.0, 100.0}, 120.0, canvas);
|
||||
configure_axis(power.get(), Axis_Orientation::vertical, {20.0, 100.0}, -80.0, canvas);
|
||||
configure_axis(time.get(), Axis_Orientation::horizontal, {20.0, 100.0}, 120.0, canvas);
|
||||
configure_axis(value.get(), Axis_Orientation::vertical, {20.0, 100.0}, -80.0, canvas);
|
||||
frequency->set<&Numeric_Axis::Prop::coordinate_range>(Axis_Range{0.0, 100.0});
|
||||
power->set<&Numeric_Axis::Prop::coordinate_range>(Axis_Range{-100.0, 0.0});
|
||||
value->set<&Numeric_Axis::Prop::coordinate_range>(Axis_Range{0.0, 100.0});
|
||||
auto trace = build_object<Trace>(not_null{time.get()},
|
||||
not_null{value.get()}, 2u);
|
||||
auto sweep = build_object<Sweep>(not_null{frequency.get()},
|
||||
not_null{power.get()}, 2u);
|
||||
trace->submit_stream<Frequency_Trace_Stream_Tag>(
|
||||
Frequency_Trace_Sample{time->append_time({1'000}), 10.0});
|
||||
trace->submit_stream<Frequency_Trace_Stream_Tag>(
|
||||
Frequency_Trace_Sample{time->append_time({2'000}), 50.0});
|
||||
trace->submit_stream<Frequency_Trace_Stream_Tag>(
|
||||
Frequency_Trace_Sample{time->append_time({3'000}), 90.0});
|
||||
trace->mark_dirty<Render_Graph_Tag>();
|
||||
sweep->set<&Sweep_Spectrum::Prop::frequency_range>(Axis_Range{0.0, 100.0});
|
||||
sweep->set<&Sweep_Spectrum::Prop::block_count>(2u);
|
||||
const std::array<Plot_Value, 4> first_block{-90.0, -60.0, -30.0, -10.0};
|
||||
const std::array<Plot_Value, 4> second_block{-80.0, -50.0, -20.0, -5.0};
|
||||
const std::array<Plot_Value, 4> replacement_block{-70.0, -40.0, -15.0, -2.0};
|
||||
sweep->submit_stream<Sweep_Spectrum_Stream_Tag>(
|
||||
std::make_shared<const Sweep_Spectrum_Block>(Sweep_Spectrum_Block{
|
||||
0, {first_block.begin(), first_block.end()}}));
|
||||
sweep->submit_stream<Sweep_Spectrum_Stream_Tag>(
|
||||
std::make_shared<const Sweep_Spectrum_Block>(Sweep_Spectrum_Block{
|
||||
1, {second_block.begin(), second_block.end()}}));
|
||||
sweep->mark_dirty<Render_Graph_Tag>();
|
||||
auto scene = build_scene<Scene>(trace.get(), sweep.get());
|
||||
scene->set<&Render_Scene_2D::Prop::viewport>(canvas);
|
||||
scene->activate_view();
|
||||
render_once(scene.get());
|
||||
EXPECT_EQ(trace->access_rendering_stream<Frequency_Trace_Stream_Tag>(
|
||||
[](std::span<Frequency_Trace_Sample> samples) { return samples.size(); }), 3u);
|
||||
EXPECT_EQ(sweep->access_rendering_stream<Sweep_Spectrum_Stream_Tag>(
|
||||
[](std::span<std::shared_ptr<const Sweep_Spectrum_Block>> blocks) { return blocks.size(); }), 2u);
|
||||
sweep->submit_stream<Sweep_Spectrum_Stream_Tag>(
|
||||
std::make_shared<const Sweep_Spectrum_Block>(Sweep_Spectrum_Block{
|
||||
0, {replacement_block.begin(), replacement_block.end()}}));
|
||||
trace->submit_stream<Frequency_Trace_Stream_Tag>(
|
||||
Frequency_Trace_Sample{time->append_time({4'000}), 60.0});
|
||||
trace->mark_dirty<Render_Graph_Tag>();
|
||||
sweep->mark_dirty<Render_Graph_Tag>();
|
||||
render_once(scene.get());
|
||||
EXPECT_EQ(trace->access_rendering_stream<Frequency_Trace_Stream_Tag>(
|
||||
[](std::span<Frequency_Trace_Sample> samples) { return samples.size(); }), 4u);
|
||||
EXPECT_EQ(sweep->access_query_stream<Sweep_Spectrum_Stream_Tag>(
|
||||
[](std::span<const std::shared_ptr<const Sweep_Spectrum_Block>> blocks) { return blocks.size(); }), 2u);
|
||||
template <typename Plot>
|
||||
Blend2D_Cache paint_plot(Plot& plot) {
|
||||
auto& private_data = aethera::detail::model_private(plot);
|
||||
private_data.advance();
|
||||
Blend2D_Cache cache;
|
||||
cache.ensure_size({120, 100});
|
||||
aethera::render_2d::detail::Painter painter(cache, {120, 100});
|
||||
private_data.paint(painter, {120, 100});
|
||||
return cache;
|
||||
}
|
||||
|
||||
TEST(plottable_migration, raster_plots_share_partitioned_color_blocks) {
|
||||
using Scene = Render_Scene_2D;
|
||||
using Frequency = Frequency_Axis;
|
||||
using Numeric = Numeric_Axis;
|
||||
using Time = Time_Axis;
|
||||
using Glow = Afterglow;
|
||||
using Fall = Waterfall;
|
||||
initialize_runtime({.workers = 2});
|
||||
const Size canvas{160, 120};
|
||||
auto frequency = build_object<Frequency>();
|
||||
auto power = build_object<Numeric>();
|
||||
auto time = build_object<Time>();
|
||||
configure_axis(frequency.get(), Axis_Orientation::horizontal, {20.0, 100.0}, 120.0, canvas);
|
||||
configure_axis(power.get(), Axis_Orientation::vertical, {20.0, 100.0}, -80.0, canvas);
|
||||
configure_axis(time.get(), Axis_Orientation::vertical, {20.0, 100.0}, -80.0, canvas);
|
||||
frequency->set<&Numeric_Axis::Prop::coordinate_range>(Axis_Range{0.0, 100.0});
|
||||
power->set<&Numeric_Axis::Prop::coordinate_range>(Axis_Range{-100.0, 0.0});
|
||||
auto glow = build_object<Glow>(not_null{frequency.get()},
|
||||
not_null{power.get()},
|
||||
Plot_Partition_Grid{2, 2});
|
||||
auto waterfall = build_object<Fall>(not_null{frequency.get()},
|
||||
not_null{time.get()},
|
||||
Plot_Partition_Grid{2, 2});
|
||||
glow->set<&Afterglow::Prop::frequency_range>(Axis_Range{0.0, 100.0});
|
||||
glow->set<&Afterglow::Prop::power_range>(Axis_Range{-100.0, 0.0});
|
||||
glow->set<&Afterglow::Prop::power_point_size>(16u);
|
||||
waterfall->set<&Waterfall::Prop::frequency_range>(Axis_Range{0.0, 100.0});
|
||||
waterfall->set<&Waterfall::Prop::power_range>(Axis_Range{-100.0, 0.0});
|
||||
const std::array<Plot_Value, 4> row{-90.0, -60.0, -30.0, -10.0};
|
||||
glow->submit_stream<Afterglow_Stream_Tag>(
|
||||
std::make_shared<const std::vector<Plot_Value>>(row.begin(), row.end()));
|
||||
glow->mark_dirty<Render_Graph_Tag>();
|
||||
waterfall->submit_stream<Waterfall_Stream_Tag>(std::make_shared<const Waterfall_Row>(
|
||||
Waterfall_Row{time->append_time({1'000}), {row.begin(), row.end()}}));
|
||||
waterfall->submit_stream<Waterfall_Stream_Tag>(std::make_shared<const Waterfall_Row>(
|
||||
Waterfall_Row{time->append_time({2'000}), {row.begin(), row.end()}}));
|
||||
waterfall->mark_dirty<Render_Graph_Tag>();
|
||||
auto scene = build_scene<Scene>(glow.get(), waterfall.get());
|
||||
scene->set<&Render_Scene_2D::Prop::viewport>(canvas);
|
||||
scene->activate_view();
|
||||
render_once(scene.get());
|
||||
EXPECT_EQ(glow->access_rendering_stream<Afterglow_Stream_Tag>(
|
||||
[](std::span<std::shared_ptr<const std::vector<Plot_Value>>> spectra) { return spectra.size(); }), 1u);
|
||||
EXPECT_EQ(waterfall->access_rendering_stream<Waterfall_Stream_Tag>(
|
||||
[](std::span<std::shared_ptr<const Waterfall_Row>> rows) { return rows.size(); }), 2u);
|
||||
glow->submit_stream<Afterglow_Stream_Tag>(
|
||||
std::make_shared<const std::vector<Plot_Value>>(row.begin(), row.end()));
|
||||
glow->mark_dirty<Render_Graph_Tag>();
|
||||
waterfall->submit_stream<Waterfall_Stream_Tag>(std::make_shared<const Waterfall_Row>(
|
||||
Waterfall_Row{time->append_time({3'000}), {row.begin(), row.end()}}));
|
||||
waterfall->mark_dirty<Render_Graph_Tag>();
|
||||
render_once(scene.get());
|
||||
EXPECT_EQ(glow->access_rendering_stream<Afterglow_Stream_Tag>(
|
||||
[](std::span<std::shared_ptr<const std::vector<Plot_Value>>> spectra) { return spectra.size(); }), 2u);
|
||||
EXPECT_EQ(waterfall->access_rendering_stream<Waterfall_Stream_Tag>(
|
||||
[](std::span<std::shared_ptr<const Waterfall_Row>> rows) { return rows.size(); }), 3u);
|
||||
bool contains_color(Image_View image) {
|
||||
for (const auto value : image.data)
|
||||
if (value != std::byte{}) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
TEST(plottable_migration, direct_overlay_and_constellation_build_and_render) {
|
||||
using Scene = Render_Scene_2D;
|
||||
using Numeric = Numeric_Axis;
|
||||
using Diagram = Constellation_Diagram;
|
||||
using Overlay = Selection_Rectangle_Overlay;
|
||||
initialize_runtime({.workers = 2});
|
||||
const Size canvas{160, 120};
|
||||
auto horizontal = build_object<Numeric>();
|
||||
auto vertical = build_object<Numeric>();
|
||||
configure_axis(horizontal.get(), Axis_Orientation::horizontal, {20.0, 100.0}, 120.0, canvas);
|
||||
configure_axis(vertical.get(), Axis_Orientation::vertical, {20.0, 100.0}, -80.0, canvas);
|
||||
horizontal->set<&Numeric_Axis::Prop::coordinate_range>(Axis_Range{-1.0, 1.0});
|
||||
vertical->set<&Numeric_Axis::Prop::coordinate_range>(Axis_Range{-1.0, 1.0});
|
||||
auto diagram = build_object<Diagram>(not_null{horizontal.get()},
|
||||
not_null{vertical.get()}, 2u);
|
||||
auto overlay = build_object<Overlay>(not_null{horizontal.get()},
|
||||
not_null{vertical.get()});
|
||||
diagram->set<&Constellation_Diagram::Prop::i_range>(Axis_Range{-1.0, 1.0});
|
||||
diagram->set<&Constellation_Diagram::Prop::q_range>(Axis_Range{-1.0, 1.0});
|
||||
diagram->submit_stream<Constellation_Stream_Tag>(
|
||||
Constellation_Point{{0.25, -0.25}, monotonic_milliseconds()});
|
||||
diagram->mark_dirty<Render_Graph_Tag>();
|
||||
auto scene = build_scene<Scene>(diagram.get(), overlay.get());
|
||||
scene->set<&Render_Scene_2D::Prop::viewport>(canvas);
|
||||
scene->activate_view();
|
||||
render_once(scene.get());
|
||||
EXPECT_EQ(diagram->access_rendering_stream<Constellation_Stream_Tag>(
|
||||
[](std::span<Constellation_Point> points) { return points.size(); }), 1u);
|
||||
}
|
||||
|
||||
TEST(selection_overlay, control_extends_selection_and_plain_click_clears_it) {
|
||||
using Scene = Render_Scene_2D;
|
||||
using Numeric = Numeric_Axis;
|
||||
using Overlay = Selection_Rectangle_Overlay;
|
||||
initialize_runtime({.workers = 2});
|
||||
const Size canvas{160, 120};
|
||||
auto horizontal = build_object<Numeric>();
|
||||
auto vertical = build_object<Numeric>();
|
||||
configure_axis(horizontal.get(), Axis_Orientation::horizontal, {20.0, 100.0}, 120.0, canvas);
|
||||
configure_axis(vertical.get(), Axis_Orientation::vertical, {20.0, 100.0}, -80.0, canvas);
|
||||
horizontal->set<&Numeric_Axis::Prop::coordinate_range>(Axis_Range{0.0, 100.0});
|
||||
vertical->set<&Numeric_Axis::Prop::coordinate_range>(Axis_Range{0.0, 100.0});
|
||||
auto overlay = build_object<Overlay>(not_null{horizontal.get()},
|
||||
not_null{vertical.get()});
|
||||
auto scene = build_scene<Scene>(overlay.get());
|
||||
scene->set<&Render_Scene_2D::Prop::viewport>(canvas);
|
||||
scene->activate_view();
|
||||
render_once(scene.get());
|
||||
|
||||
const auto drag = [&](Point_F first, Point_F second, Keyboard_Modifier modifiers) {
|
||||
auto press = scene->make_event<Pointer_Event>(Event_Type::pointer_press);
|
||||
press->position = first;
|
||||
press->button = Mouse_Button::left;
|
||||
press->modifiers = modifiers;
|
||||
scene->submit_stream<Scene_Event_Stream_Tag>(press);
|
||||
auto move = scene->make_event<Pointer_Event>(Event_Type::pointer_move);
|
||||
move->position = second;
|
||||
move->modifiers = modifiers;
|
||||
scene->submit_stream<Scene_Event_Stream_Tag>(move);
|
||||
auto release = scene->make_event<Pointer_Event>(Event_Type::pointer_release);
|
||||
release->position = second;
|
||||
release->button = Mouse_Button::left;
|
||||
release->modifiers = modifiers;
|
||||
scene->submit_stream<Scene_Event_Stream_Tag>(release);
|
||||
render_once(scene.get());
|
||||
};
|
||||
drag({30.0, 90.0}, {60.0, 60.0}, Keyboard_Modifier::none);
|
||||
EXPECT_EQ(overlay->read_prop<Selection_Rectangle_Overlay::Base_Tag>().selected_regions.size(), 1u);
|
||||
drag({70.0, 90.0}, {100.0, 60.0}, Keyboard_Modifier::control);
|
||||
EXPECT_EQ(overlay->read_prop<Selection_Rectangle_Overlay::Base_Tag>().selected_regions.size(), 2u);
|
||||
drag({120.0, 40.0}, {120.0, 40.0}, Keyboard_Modifier::none);
|
||||
EXPECT_TRUE(overlay->read_prop<Selection_Rectangle_Overlay::Base_Tag>().selected_regions.empty());
|
||||
}
|
||||
|
||||
TEST(selection_overlay, time_axis_selection_keeps_axis_coordinates_while_window_moves) {
|
||||
using Scene = Render_Scene_2D;
|
||||
using Time = Time_Axis;
|
||||
using Numeric = Numeric_Axis;
|
||||
using Overlay = Selection_Rectangle_Overlay;
|
||||
initialize_runtime({.workers = 2});
|
||||
const Size canvas{160, 120};
|
||||
auto time = build_object<Time>();
|
||||
auto value = build_object<Numeric>();
|
||||
configure_axis(time.get(), Axis_Orientation::horizontal, {20.0, 100.0}, 120.0, canvas);
|
||||
configure_axis(value.get(), Axis_Orientation::vertical, {20.0, 100.0}, -80.0, canvas);
|
||||
time->set<&Time_Axis::Prop::visible_count>(10);
|
||||
value->set<&Numeric_Axis::Prop::coordinate_range>(Axis_Range{0.0, 100.0});
|
||||
TEST(Plottable_Migration, Frequency_Trace_And_Sweep_Use_Import_Lists) {
|
||||
auto time = Time_Axis::Builder{}.build();
|
||||
auto value = make_axis<Numeric_Axis>(Axis_Orientation::vertical, {0.0, 100.0});
|
||||
time->set<Prop_Tag>(&Abs_Axis::Prop::position, Point_F{10.0, 90.0});
|
||||
time->set<Prop_Tag>(&Abs_Axis::Prop::pixel_length, 100.0);
|
||||
time->append_time({1'000});
|
||||
time->append_time({2'000});
|
||||
time->append_time({3'000});
|
||||
auto overlay = build_object<Overlay>(not_null{time.get()},
|
||||
not_null{value.get()});
|
||||
auto scene = build_scene<Scene>(overlay.get());
|
||||
scene->set<&Render_Scene_2D::Prop::viewport>(canvas);
|
||||
scene->activate_view();
|
||||
render_once(scene.get());
|
||||
auto press = scene->make_event<Pointer_Event>(Event_Type::pointer_press);
|
||||
press->position = {92.0, 88.0};
|
||||
press->button = Mouse_Button::left;
|
||||
scene->submit_stream<Scene_Event_Stream_Tag>(press);
|
||||
auto move = scene->make_event<Pointer_Event>(Event_Type::pointer_move);
|
||||
move->position = {116.0, 56.0};
|
||||
scene->submit_stream<Scene_Event_Stream_Tag>(move);
|
||||
auto release = scene->make_event<Pointer_Event>(Event_Type::pointer_release);
|
||||
release->position = {116.0, 56.0};
|
||||
release->button = Mouse_Button::left;
|
||||
scene->submit_stream<Scene_Event_Stream_Tag>(release);
|
||||
render_once(scene.get());
|
||||
ASSERT_EQ(overlay->read_prop<Selection_Rectangle_Overlay::Base_Tag>().selected_regions.size(), 1u);
|
||||
const Axis_Rectangle selected = overlay->read_prop<Selection_Rectangle_Overlay::Base_Tag>().selected_regions.front();
|
||||
const auto pixel_before = time->coordinate_to_pixel(selected.horizontal.center());
|
||||
time->append_time({4'000});
|
||||
render_once(scene.get());
|
||||
ASSERT_EQ(overlay->read_prop<Selection_Rectangle_Overlay::Base_Tag>().selected_regions.size(), 1u);
|
||||
EXPECT_EQ(overlay->read_prop<Selection_Rectangle_Overlay::Base_Tag>().selected_regions.front(), selected);
|
||||
EXPECT_NE(time->coordinate_to_pixel(selected.horizontal.center()), pixel_before);
|
||||
aethera::detail::model_private(*time).advance();
|
||||
Frequency_Trace::Builder trace_builder(*time, *value);
|
||||
auto trace = trace_builder.build();
|
||||
trace->set<Frequency_Trace_Stream_Tag>([](Frequency_Trace::Samples& samples) { samples.push_back({0, 10.0}); samples.push_back({1, 80.0}); });
|
||||
EXPECT_TRUE(contains_color(paint_plot(*trace).view()));
|
||||
Frequency_Trace::State trace_state;
|
||||
trace->get<State_Tag>([&](const Frequency_Trace::State& state) { trace_state = state; });
|
||||
EXPECT_EQ(trace_state.sample_count, 2U);
|
||||
|
||||
auto frequency = make_axis<Frequency_Axis>(Axis_Orientation::horizontal, {0.0, 100.0});
|
||||
auto power = make_axis<Numeric_Axis>(Axis_Orientation::vertical, {-100.0, 0.0});
|
||||
Sweep_Spectrum::Builder sweep_builder(*frequency, *power);
|
||||
sweep_builder
|
||||
.set<Prop_Tag>(&Sweep_Spectrum::Prop::frequency_range, Axis_Range{0.0, 100.0})
|
||||
.set<Prop_Tag>(&Sweep_Spectrum::Prop::block_count, 2U);
|
||||
auto sweep = sweep_builder.build();
|
||||
sweep->set<Sweep_Spectrum_Stream_Tag>([](Sweep_Spectrum::Blocks& blocks) { blocks.push_back(std::make_shared<const Sweep_Spectrum_Block>(Sweep_Spectrum_Block{0, {-90.0, -40.0}})); blocks.push_back(std::make_shared<const Sweep_Spectrum_Block>(Sweep_Spectrum_Block{1, {-30.0, -10.0}})); });
|
||||
EXPECT_TRUE(contains_color(paint_plot(*sweep).view()));
|
||||
Sweep_Spectrum::State sweep_state;
|
||||
sweep->get<State_Tag>([&](const Sweep_Spectrum::State& state) { sweep_state = state; });
|
||||
EXPECT_EQ(sweep_state.stored_block_count, 2U);
|
||||
}
|
||||
|
||||
TEST(Plottable_Migration, Raster_Plots_Keep_One_Private_History) {
|
||||
auto frequency = make_axis<Frequency_Axis>(Axis_Orientation::horizontal, {0.0, 100.0});
|
||||
auto power = make_axis<Numeric_Axis>(Axis_Orientation::vertical, {-100.0, 0.0});
|
||||
Afterglow::Builder glow_builder(*frequency, *power);
|
||||
glow_builder
|
||||
.set<Prop_Tag>(&Afterglow::Prop::frequency_range, Axis_Range{0.0, 100.0})
|
||||
.set<Prop_Tag>(&Afterglow::Prop::power_range, Axis_Range{-100.0, 0.0})
|
||||
.set<Prop_Tag>(&Afterglow::Prop::power_point_size, 16U)
|
||||
.set<Prop_Tag>(&Afterglow::Prop::partition_grid, Plot_Partition_Grid{2, 2});
|
||||
auto glow = glow_builder.build();
|
||||
glow->set<Afterglow_Stream_Tag>([](Afterglow::Spectra& spectra) { spectra.push_back(std::make_shared<const std::vector<Plot_Value>>(std::vector<Plot_Value>{-90.0, -60.0, -30.0, -10.0})); });
|
||||
EXPECT_TRUE(contains_color(paint_plot(*glow).view()));
|
||||
|
||||
auto time = Time_Axis::Builder{}.build();
|
||||
time->set<Prop_Tag>(&Abs_Axis::Prop::position, Point_F{10.0, 90.0});
|
||||
time->set<Prop_Tag>(&Abs_Axis::Prop::pixel_length, -80.0);
|
||||
time->set<Prop_Tag>(&Abs_Axis::Prop::orientation, Axis_Orientation::vertical);
|
||||
const auto first_tick = time->append_time({1'000});
|
||||
const auto second_tick = time->append_time({2'000});
|
||||
aethera::detail::model_private(*time).advance();
|
||||
Waterfall::Builder waterfall_builder(*frequency, *time);
|
||||
waterfall_builder
|
||||
.set<Prop_Tag>(&Waterfall::Prop::frequency_range, Axis_Range{0.0, 100.0})
|
||||
.set<Prop_Tag>(&Waterfall::Prop::power_range, Axis_Range{-100.0, 0.0})
|
||||
.set<Prop_Tag>(&Waterfall::Prop::partition_grid, Plot_Partition_Grid{2, 2});
|
||||
auto waterfall = waterfall_builder.build();
|
||||
waterfall->set<Waterfall_Stream_Tag>([first_tick, second_tick](Waterfall::Rows& rows) { rows.push_back(std::make_shared<const Waterfall_Row>(Waterfall_Row{first_tick, {-90.0, -60.0, -30.0, -10.0}})); rows.push_back(std::make_shared<const Waterfall_Row>(Waterfall_Row{second_tick, {-80.0, -50.0, -20.0, -5.0}})); });
|
||||
EXPECT_TRUE(contains_color(paint_plot(*waterfall).view()));
|
||||
}
|
||||
|
||||
TEST(Plottable_Migration, Constellation_And_Overlay_Use_Virtual_Private_Runtime) {
|
||||
auto horizontal = make_axis<Numeric_Axis>(Axis_Orientation::horizontal, {-1.0, 1.0});
|
||||
auto vertical = make_axis<Numeric_Axis>(Axis_Orientation::vertical, {-1.0, 1.0});
|
||||
const auto now = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now().time_since_epoch()).count();
|
||||
Constellation_Diagram::Builder diagram_builder(*horizontal, *vertical);
|
||||
diagram_builder
|
||||
.set<Prop_Tag>(&Constellation_Diagram::Prop::i_range, Axis_Range{-1.0, 1.0})
|
||||
.set<Prop_Tag>(&Constellation_Diagram::Prop::q_range, Axis_Range{-1.0, 1.0});
|
||||
auto diagram = diagram_builder.build();
|
||||
diagram->set<Constellation_Stream_Tag>([now](Constellation_Diagram::Points& points) { points.push_back({{0.25, -0.25}, now}); });
|
||||
EXPECT_TRUE(contains_color(paint_plot(*diagram).view()));
|
||||
|
||||
Selection_Rectangle_Overlay::Builder overlay_builder(*horizontal, *vertical);
|
||||
auto overlay = overlay_builder.build();
|
||||
auto& overlay_private = aethera::detail::model_private(*overlay);
|
||||
Pointer_Event press{Event_Type::pointer_press};
|
||||
press.position = {20.0, 80.0};
|
||||
press.button = Mouse_Button::left;
|
||||
overlay_private.dispatch_event(press);
|
||||
Pointer_Event move{Event_Type::pointer_move};
|
||||
move.position = {60.0, 40.0};
|
||||
overlay_private.dispatch_event(move);
|
||||
Pointer_Event release{Event_Type::pointer_release};
|
||||
release.position = move.position;
|
||||
release.button = Mouse_Button::left;
|
||||
overlay_private.dispatch_event(release);
|
||||
overlay_private.advance();
|
||||
std::size_t selected{};
|
||||
overlay->get<Prop_Tag>([&](const Selection_Rectangle_Overlay::Prop& properties) { selected = properties.selected_regions.size(); });
|
||||
EXPECT_EQ(selected, 1U);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
Reference in New Issue
Block a user