改结构
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
#pragma once
|
||||
#include "../render/Blend2D_Cache.hpp"
|
||||
#include <renderable.hpp>
|
||||
#include <expected>
|
||||
#include <functional>
|
||||
namespace aethera::render_2d {
|
||||
/* 二维 Renderable 是否拥有可跨帧复用的完整颜色缓存。 */
|
||||
enum class Renderable_2D_Cache {
|
||||
|
||||
@@ -2,10 +2,12 @@
|
||||
#include <stdexcept>
|
||||
namespace aethera::render_2d {
|
||||
struct Renderable_2D<Renderable_2D_Cache::disabled>::Private : Prev_Private {
|
||||
using Scene_Attach = std::function<std::expected<void, Dependency_Graph_Error>(Root*)>;
|
||||
using Cache_Access = Blend2D_Cache* (*)(Root*);
|
||||
Cache_Access pending_cache{}; /* 非空时返回最终对象本轮可写的缓存物理对象。 */
|
||||
Blend2D_Cache* paint_target{}; /* 仅在 Scene Paint 阶段有效的非拥有绘制目标。 */
|
||||
Blend2D_Cache* valid_cache{}; /* 缓存根最近一次完整重绘产生的权威物理缓存。 */
|
||||
Scene_Attach scene_attach{}; /* Scene Builder 在构造期执行的所属场景及拓扑绑定。 */
|
||||
/* Paint 实现使用:返回 Scene 为本轮指定的目标;未进入 Paint 阶段属于契约错误。 */
|
||||
[[nodiscard]] Blend2D_Cache& paint_surface();
|
||||
/* CRTP 覆盖:识别最终类型是否选择了二维颜色缓存。 */
|
||||
@@ -24,6 +26,7 @@ inline Blend2D_Cache& Renderable_2D<Renderable_2D_Cache::disabled>::Private::pai
|
||||
template <Attached Object>
|
||||
void Renderable_2D<Renderable_2D_Cache::disabled>::Private::bind_private_crtp(Object* object) {
|
||||
Prev_Private::bind_private_crtp(object);
|
||||
object->template mark_dirty<Paint_Tag>();
|
||||
}
|
||||
template <Attached Object>
|
||||
void Renderable_2D<Renderable_2D_Cache::enabled>::Private::bind_private_crtp(Object* object) {
|
||||
|
||||
@@ -33,10 +33,9 @@ struct Afterglow : Def<Afterglow, Renderable_2D<Renderable_2D_Cache::enabled>> {
|
||||
struct Private;
|
||||
template <typename Object> struct Builder : Prev_Builder<Object> {
|
||||
using Base = Prev_Builder<Object>;
|
||||
Builder(Scene_Object* scene, Frequency_Object* frequency_axis, Power_Object* power_axis);
|
||||
Builder(Frequency_Object* frequency_axis, Power_Object* power_axis);
|
||||
[[nodiscard]] std::expected<std::unique_ptr<Object>, Dependency_Graph_Error> build();
|
||||
private:
|
||||
Scene_Object* scene{}; /* 不拥有的所属 Scene;生命周期必须覆盖 Afterglow。 */
|
||||
Frequency_Object* frequency_axis{}; /* 不拥有的频率轴;生命周期必须覆盖 Afterglow。 */
|
||||
Power_Object* power_axis{}; /* 不拥有的功率轴;生命周期必须覆盖 Afterglow。 */
|
||||
};
|
||||
|
||||
@@ -27,7 +27,7 @@ struct Afterglow::Private : Prev_Private {
|
||||
const Dispatch* dispatch{}; /* 最终类型的公开薄壳分派表。 */
|
||||
/* CRTP 覆盖:绑定 Renderable 能力和最终 Afterglow 分派表。 */
|
||||
template <Attached Object> void bind_private_crtp(Object* object);
|
||||
void bind_sources(Scene_Object* scene_value, Frequency_Object* frequency_axis_value, Power_Object* power_axis_value);
|
||||
void bind_sources(Frequency_Object* frequency_axis_value, Power_Object* power_axis_value);
|
||||
template <Attached Object> [[nodiscard]] static const Dispatch& dispatch_for();
|
||||
/* CRTP 覆盖:构建累加、归一化和着色三阶段 Prepare 子图。 */
|
||||
template <Attached Object> [[nodiscard]] tf::Taskflow build_prepare_graph(Object* object, const Prop& state);
|
||||
@@ -40,9 +40,16 @@ struct Afterglow::Private : Prev_Private {
|
||||
template <typename Object, typename Owner, typename Member, typename Prop_Type> void after_prop_set(Object* object, Member Owner::* member, Prop_Access<Prop_Type> states);
|
||||
template <typename Object, typename Prop_Type, typename State_Type> void before_advance(Object* object, Prop_Type* pending_prop, State_Access<State_Type> pending_states, const Prop_Type* current_prop, State_Access<const State_Type> current_states);
|
||||
};
|
||||
template <typename Object> Afterglow::Builder<Object>::Builder(Scene_Object* scene_value, Frequency_Object* frequency_axis_value, Power_Object* power_axis_value) : Base(), scene(scene_value), frequency_axis(frequency_axis_value), power_axis(power_axis_value) {}
|
||||
template <typename Object> Afterglow::Builder<Object>::Builder(Frequency_Object* frequency_axis_value, Power_Object* power_axis_value) : Base(), frequency_axis(frequency_axis_value), power_axis(power_axis_value) {}
|
||||
template <typename Object>
|
||||
std::expected<std::unique_ptr<Object>, Dependency_Graph_Error> Afterglow::Builder<Object>::build() { auto result = Base::build(); if (!result) return std::unexpected(result.error()); auto plot = std::move(result).value(); static_cast<typename Object::Private&>(*plot->d).bind_sources(scene, frequency_axis, power_axis); auto graph_result = scene->template edit_dependency_graph<Prepare_Data_Tag, Paint_Tag, Paint_Cache_Tag>([&](auto& prepare, auto& paint, auto& cache) { prepare.add_dependency(plot.get(), scene); prepare.add_dependency(plot.get(), frequency_axis); prepare.add_dependency(plot.get(), power_axis); paint.add_dependency(frequency_axis, plot.get()); paint.add_dependency(power_axis, plot.get()); cache.template add_prop_dependency<&Render_Scene_2D::Prop::viewport>(plot.get(), scene); cache.template add_prop_dependency<&Abs_Axis::Prop::position>(plot.get(), frequency_axis); cache.template add_prop_dependency<&Abs_Axis::Prop::pixel_length>(plot.get(), frequency_axis); cache.template add_prop_dependency<&Abs_Axis::Prop::orientation>(plot.get(), frequency_axis); cache.template add_prop_dependency<&Numeric_Axis::Prop::coordinate_range>(plot.get(), frequency_axis); cache.template add_prop_dependency<&Abs_Axis::Prop::position>(plot.get(), power_axis); cache.template add_prop_dependency<&Abs_Axis::Prop::pixel_length>(plot.get(), power_axis); cache.template add_prop_dependency<&Abs_Axis::Prop::orientation>(plot.get(), power_axis); cache.template add_prop_dependency<&Numeric_Axis::Prop::coordinate_range>(plot.get(), power_axis); }); if (!graph_result) return std::unexpected(graph_result.error()); return std::move(plot); }
|
||||
std::expected<std::unique_ptr<Object>, Dependency_Graph_Error> Afterglow::Builder<Object>::build() {
|
||||
auto result = Base::build(); if (!result) return std::unexpected(result.error()); auto plot = std::move(result).value();
|
||||
auto& private_data = static_cast<typename Object::Private&>(*plot->d); private_data.bind_sources(frequency_axis, power_axis);
|
||||
private_data.scene_attach = [object = plot.get()](Root* root) -> std::expected<void, Dependency_Graph_Error> {
|
||||
auto* scene = static_cast<Scene_Object*>(root); auto& data = static_cast<typename Object::Private&>(*object->d); data.scene = scene; auto* frequency_axis = data.frequency_axis; auto* power_axis = data.power_axis;
|
||||
return scene->template edit_dependency_graph<Prepare_Data_Tag, Paint_Tag, Paint_Cache_Tag>([&](auto& prepare, auto& paint, auto& cache) { prepare.add_dependency(object, scene); prepare.add_dependency(object, frequency_axis); prepare.add_dependency(object, power_axis); paint.add_dependency(frequency_axis, object); paint.add_dependency(power_axis, object); cache.template add_prop_dependency<&Render_Scene_2D::Prop::viewport>(object, scene); cache.template add_prop_dependency<&Abs_Axis::Prop::position>(object, frequency_axis); cache.template add_prop_dependency<&Abs_Axis::Prop::pixel_length>(object, frequency_axis); cache.template add_prop_dependency<&Abs_Axis::Prop::orientation>(object, frequency_axis); cache.template add_prop_dependency<&Numeric_Axis::Prop::coordinate_range>(object, frequency_axis); cache.template add_prop_dependency<&Abs_Axis::Prop::position>(object, power_axis); cache.template add_prop_dependency<&Abs_Axis::Prop::pixel_length>(object, power_axis); cache.template add_prop_dependency<&Abs_Axis::Prop::orientation>(object, power_axis); cache.template add_prop_dependency<&Numeric_Axis::Prop::coordinate_range>(object, power_axis); });
|
||||
}; return plot;
|
||||
}
|
||||
template <typename Values> void Afterglow::append_spectrum(const Values& values) { append_spectrum(std::span<const Plot_Value>(std::data(values), std::size(values))); }
|
||||
template <Attached Object> bool Afterglow::Private::should_rebuild_prepare_graph(Object*, const Prop& state) { const std::size_t available = state.spectra.empty() ? 0 : state.spectra.back().size(); const std::size_t columns = state.frequency_point_size ? std::min(state.frequency_point_size, available) : available; return graph_partition_count != detail::curve_partition_count(state.partition_mode, state.partition_count, std::max<std::size_t>(1, columns)); }
|
||||
template <Attached Object>
|
||||
@@ -61,5 +68,5 @@ template <typename Object, typename Prop_Type, typename State_Type> void Aftergl
|
||||
template <Attached Object>
|
||||
const Afterglow::Private::Dispatch& Afterglow::Private::dispatch_for() { static const Dispatch value{[](Root* root, std::span<const Plot_Value> values) { auto* object = static_cast<Object*>(root); object->template update_prop<&Prop::spectra>([values](Prop_Access<typename Object::Prop> props) { auto& state = props.template get<Afterglow::Base_Tag>(); state.spectra.emplace_back(values.begin(), values.end()); constexpr std::size_t history_limit = 64; while (state.spectra.size() > history_limit) state.spectra.erase(state.spectra.begin()); }); }, [](const Root* root) { return static_cast<const Object*>(root)->template read_prop<Afterglow::Base_Tag>().spectra.size(); }, [](const Root* root) { const auto& spectra = static_cast<const Object*>(root)->template read_prop<Afterglow::Base_Tag>().spectra; return spectra.empty() ? 0 : spectra.back().size(); }, [](const Root* root) { const auto& data = static_cast<const typename Object::Private&>(*static_cast<const Object*>(root)->d); return data.prepared.valid ? data.prepared.pixels.size() : 0; }}; return value; }
|
||||
template <Attached Object> void Afterglow::Private::bind_private_crtp(Object* object) { Prev_Private::bind_private_crtp(object); dispatch = &dispatch_for<Object>(); }
|
||||
inline void Afterglow::Private::bind_sources(Scene_Object* scene_value, Frequency_Object* frequency_axis_value, Power_Object* power_axis_value) { scene = scene_value; frequency_axis = frequency_axis_value; power_axis = power_axis_value; }
|
||||
inline void Afterglow::Private::bind_sources(Frequency_Object* frequency_axis_value, Power_Object* power_axis_value) { frequency_axis = frequency_axis_value; power_axis = power_axis_value; }
|
||||
}
|
||||
|
||||
@@ -29,10 +29,9 @@ struct Constellation_Diagram : Def<Constellation_Diagram, Renderable_2D<Renderab
|
||||
struct Private;
|
||||
template <typename Object> struct Builder : Prev_Builder<Object> {
|
||||
using Base = Prev_Builder<Object>;
|
||||
Builder(Scene_Object* scene, Axis_Object* i_axis, Axis_Object* q_axis);
|
||||
Builder(Axis_Object* i_axis, Axis_Object* q_axis);
|
||||
[[nodiscard]] std::expected<std::unique_ptr<Object>, Dependency_Graph_Error> build();
|
||||
private:
|
||||
Scene_Object* scene{}; /* 不拥有的所属 Scene;生命周期必须覆盖星座图。 */
|
||||
Axis_Object* i_axis{}; /* 不拥有的同相分量轴;生命周期必须覆盖星座图。 */
|
||||
Axis_Object* q_axis{}; /* 不拥有的正交分量轴;生命周期必须覆盖星座图。 */
|
||||
};
|
||||
|
||||
@@ -23,7 +23,7 @@ struct Constellation_Diagram::Private : Prev_Private {
|
||||
const Dispatch* dispatch{}; /* 最终类型的公开薄壳分派表。 */
|
||||
/* CRTP 覆盖:绑定 Renderable 能力和最终 Constellation 分派表。 */
|
||||
template <Attached Object> void bind_private_crtp(Object* object);
|
||||
void bind_sources(Scene_Object* scene_value, Axis_Object* i_axis_value, Axis_Object* q_axis_value);
|
||||
void bind_sources(Axis_Object* i_axis_value, Axis_Object* q_axis_value);
|
||||
template <Attached Object> [[nodiscard]] static const Dispatch& dispatch_for();
|
||||
/* CRTP 覆盖:从当前点集和轴状态准备画布坐标。 */
|
||||
template <Attached Object> void prepare_data(Object* object);
|
||||
@@ -33,9 +33,9 @@ struct Constellation_Diagram::Private : Prev_Private {
|
||||
template <typename Object, typename Owner, typename Member, typename Prop_Type> void after_prop_set(Object* object, Member Owner::* member, Prop_Access<Prop_Type> states);
|
||||
template <typename Object, typename Prop_Type, typename State_Type> void before_advance(Object* object, Prop_Type* pending_prop, State_Access<State_Type> pending_states, const Prop_Type* current_prop, State_Access<const State_Type> current_states);
|
||||
};
|
||||
template <typename Object> Constellation_Diagram::Builder<Object>::Builder(Scene_Object* scene_value, Axis_Object* i_axis_value, Axis_Object* q_axis_value) : Base(), scene(scene_value), i_axis(i_axis_value), q_axis(q_axis_value) {}
|
||||
template <typename Object> Constellation_Diagram::Builder<Object>::Builder(Axis_Object* i_axis_value, Axis_Object* q_axis_value) : Base(), i_axis(i_axis_value), q_axis(q_axis_value) {}
|
||||
template <typename Object>
|
||||
std::expected<std::unique_ptr<Object>, Dependency_Graph_Error> Constellation_Diagram::Builder<Object>::build() { auto result = Base::build(); if (!result) return std::unexpected(result.error()); auto plot = std::move(result).value(); static_cast<typename Object::Private&>(*plot->d).bind_sources(scene, i_axis, q_axis); auto graph_result = scene->template edit_dependency_graph<Prepare_Data_Tag, Paint_Tag, Paint_Cache_Tag>([&](auto& prepare, auto& paint, auto& cache) { prepare.add_dependency(plot.get(), scene); prepare.add_dependency(plot.get(), i_axis); prepare.add_dependency(plot.get(), q_axis); paint.add_dependency(i_axis, plot.get()); paint.add_dependency(q_axis, plot.get()); cache.template add_prop_dependency<&Render_Scene_2D::Prop::viewport>(plot.get(), scene); cache.template add_prop_dependency<&Abs_Axis::Prop::position>(plot.get(), i_axis); cache.template add_prop_dependency<&Abs_Axis::Prop::pixel_length>(plot.get(), i_axis); cache.template add_prop_dependency<&Abs_Axis::Prop::orientation>(plot.get(), i_axis); cache.template add_prop_dependency<&Numeric_Axis::Prop::coordinate_range>(plot.get(), i_axis); cache.template add_prop_dependency<&Abs_Axis::Prop::position>(plot.get(), q_axis); cache.template add_prop_dependency<&Abs_Axis::Prop::pixel_length>(plot.get(), q_axis); cache.template add_prop_dependency<&Abs_Axis::Prop::orientation>(plot.get(), q_axis); cache.template add_prop_dependency<&Numeric_Axis::Prop::coordinate_range>(plot.get(), q_axis); }); if (!graph_result) return std::unexpected(graph_result.error()); return std::move(plot); }
|
||||
std::expected<std::unique_ptr<Object>, Dependency_Graph_Error> Constellation_Diagram::Builder<Object>::build() { auto result = Base::build(); if (!result) return std::unexpected(result.error()); auto plot = std::move(result).value(); auto& private_data = static_cast<typename Object::Private&>(*plot->d); private_data.bind_sources(i_axis, q_axis); private_data.scene_attach = [object = plot.get()](Root* root) -> std::expected<void, Dependency_Graph_Error> { auto* scene = static_cast<Scene_Object*>(root); auto& data = static_cast<typename Object::Private&>(*object->d); data.scene = scene; auto* i_axis = data.i_axis; auto* q_axis = data.q_axis; return scene->template edit_dependency_graph<Prepare_Data_Tag, Paint_Tag, Paint_Cache_Tag>([&](auto& prepare, auto& paint, auto& cache) { prepare.add_dependency(object, scene); prepare.add_dependency(object, i_axis); prepare.add_dependency(object, q_axis); paint.add_dependency(i_axis, object); paint.add_dependency(q_axis, object); cache.template add_prop_dependency<&Render_Scene_2D::Prop::viewport>(object, scene); cache.template add_prop_dependency<&Abs_Axis::Prop::position>(object, i_axis); cache.template add_prop_dependency<&Abs_Axis::Prop::pixel_length>(object, i_axis); cache.template add_prop_dependency<&Abs_Axis::Prop::orientation>(object, i_axis); cache.template add_prop_dependency<&Numeric_Axis::Prop::coordinate_range>(object, i_axis); cache.template add_prop_dependency<&Abs_Axis::Prop::position>(object, q_axis); cache.template add_prop_dependency<&Abs_Axis::Prop::pixel_length>(object, q_axis); cache.template add_prop_dependency<&Abs_Axis::Prop::orientation>(object, q_axis); cache.template add_prop_dependency<&Numeric_Axis::Prop::coordinate_range>(object, q_axis); }); }; return plot; }
|
||||
template <Attached Object>
|
||||
void Constellation_Diagram::Private::prepare_data(Object* object) { const auto& state = object->template read_prop<Constellation_Diagram::Base_Tag>(); const auto& i_layout = i_axis->template read_prop<Abs_Axis::Base_Tag>(); const auto& q_layout = q_axis->template read_prop<Abs_Axis::Base_Tag>(); prepared = {}; prepared.canvas = scene->template read_prop<Render_Scene_2D::Base_Tag>().viewport; if (prepared.canvas.empty() || i_layout.orientation == q_layout.orientation) return; const auto current = monotonic_milliseconds(); for (const auto& value : state.points) if (current - value.submitted_at_ms <= state.point_lifetime_ms) prepared.points.push_back(detail::map_plot_point(i_axis, value.point.x, q_axis, value.point.y, i_layout.orientation)); const int count = static_cast<int>(state.type); const Plot_Coordinate center_i = state.i_range.center(); const Plot_Coordinate center_q = state.q_range.center(); const Plot_Coordinate radius = std::min(state.i_range.size(), state.q_range.size()) * 0.4; for (int index = 0; index < count; ++index) { const Plot_Ratio angle = state.phase_offset_radians + 2.0 * std::numbers::pi * index / count; prepared.anchors.push_back(detail::map_plot_point(i_axis, center_i + std::cos(angle) * radius, q_axis, center_q + std::sin(angle) * radius, i_layout.orientation)); } prepared.valid = true; object->template mark_dirty<Paint_Tag>(); }
|
||||
template <Attached Object> void Constellation_Diagram::Private::paint(Object* object) { const auto& state = object->template read_prop<Constellation_Diagram::Base_Tag>(); auto& cache = this->paint_surface(); if (!prepared.valid) return; detail::Painter painter(cache, prepared.canvas); for (const auto& anchor : prepared.anchors) painter.circle(anchor, 4.0, Pen{state.anchor_color}, Brush{state.anchor_color, Brush_Style::solid}); for (const auto& point : prepared.points) painter.circle(point, 2.0, Pen{state.point_color}, Brush{state.point_color, Brush_Style::solid}); }
|
||||
@@ -44,5 +44,5 @@ template <typename Object, typename Prop_Type, typename State_Type> void Constel
|
||||
template <Attached Object>
|
||||
const Constellation_Diagram::Private::Dispatch& Constellation_Diagram::Private::dispatch_for() { static const Dispatch value{[](Root* root, Point_F point) { auto* object = static_cast<Object*>(root); const auto submitted = monotonic_milliseconds(); object->template update_prop<&Prop::points>([=](Prop_Access<typename Object::Prop> props) { auto& state = props.template get<Constellation_Diagram::Base_Tag>(); state.points.erase(std::remove_if(state.points.begin(), state.points.end(), [=](const auto& value) { return submitted - value.submitted_at_ms > state.point_lifetime_ms; }), state.points.end()); state.points.push_back({point, submitted}); }); }, [](const Root* root) { return static_cast<const Object*>(root)->template read_prop<Constellation_Diagram::Base_Tag>().points.size(); }, [](Root* root) { auto* object = static_cast<Object*>(root); auto& data = static_cast<typename Object::Private&>(*object->d); const auto& state = object->template read_prop<Constellation_Diagram::Base_Tag>(); const Plot_Coordinate size = std::max(state.i_range.size(), state.q_range.size()); const Plot_Coordinate i_center = state.i_range.center(); const Plot_Coordinate q_center = state.q_range.center(); data.i_axis->template set<&Numeric_Axis::Prop::coordinate_range>(Axis_Range{i_center - size * 0.5, i_center + size * 0.5}); data.q_axis->template set<&Numeric_Axis::Prop::coordinate_range>(Axis_Range{q_center - size * 0.5, q_center + size * 0.5}); }}; return value; }
|
||||
template <Attached Object> void Constellation_Diagram::Private::bind_private_crtp(Object* object) { Prev_Private::bind_private_crtp(object); dispatch = &dispatch_for<Object>(); }
|
||||
inline void Constellation_Diagram::Private::bind_sources(Scene_Object* scene_value, Axis_Object* i_axis_value, Axis_Object* q_axis_value) { scene = scene_value; i_axis = i_axis_value; q_axis = q_axis_value; }
|
||||
inline void Constellation_Diagram::Private::bind_sources(Axis_Object* i_axis_value, Axis_Object* q_axis_value) { i_axis = i_axis_value; q_axis = q_axis_value; }
|
||||
}
|
||||
|
||||
@@ -32,10 +32,9 @@ struct Frequency_Trace : Def<Frequency_Trace, Renderable_2D<Renderable_2D_Cache:
|
||||
template <typename Object>
|
||||
struct Builder : Prev_Builder<Object> {
|
||||
using Base = Prev_Builder<Object>;
|
||||
Builder(Scene_Object* scene, Time_Object* time_axis, Value_Object* value_axis);
|
||||
Builder(Time_Object* time_axis, Value_Object* value_axis);
|
||||
[[nodiscard]] std::expected<std::unique_ptr<Object>, Dependency_Graph_Error> build();
|
||||
private:
|
||||
Scene_Object* scene{}; /* 不拥有的所属 Scene。 */
|
||||
Time_Object* time_axis{}; /* 不拥有的时间轴。 */
|
||||
Value_Object* value_axis{}; /* 不拥有的数值轴。 */
|
||||
};
|
||||
|
||||
@@ -26,7 +26,7 @@ struct Frequency_Trace::Private : Prev_Private {
|
||||
const Dispatch* dispatch{}; /* 最终类型公开薄壳分派表。 */
|
||||
/* CRTP 覆盖:绑定 Renderable 能力和最终 Frequency_Trace 分派表。 */
|
||||
template <Attached Object> void bind_private_crtp(Object* object);
|
||||
void bind_sources(Scene_Object* scene_value, Time_Object* time_axis_value, Value_Object* value_axis_value);
|
||||
void bind_sources(Time_Object* time_axis_value, Value_Object* value_axis_value);
|
||||
template <Attached Object> [[nodiscard]] static const Dispatch& dispatch_for();
|
||||
/* CRTP 覆盖:按当前样本规模构建分块 Prepare 子图。 */
|
||||
template <Attached Object> [[nodiscard]] tf::Taskflow build_prepare_graph(Object* object, const Prop& state);
|
||||
@@ -42,20 +42,11 @@ struct Frequency_Trace::Private : Prev_Private {
|
||||
template <typename Object, typename Prop_Type, typename State_Type> void before_advance(Object* object, Prop_Type* pending_prop, State_Access<State_Type> pending_states, const Prop_Type* current_prop, State_Access<const State_Type> current_states);
|
||||
};
|
||||
template <typename Object>
|
||||
Frequency_Trace::Builder<Object>::Builder(Scene_Object* scene_value, Time_Object* time_axis_value, Value_Object* value_axis_value) : Base(), scene(scene_value), time_axis(time_axis_value), value_axis(value_axis_value) {}
|
||||
Frequency_Trace::Builder<Object>::Builder(Time_Object* time_axis_value, Value_Object* value_axis_value) : Base(), time_axis(time_axis_value), value_axis(value_axis_value) {}
|
||||
template <typename Object>
|
||||
std::expected<std::unique_ptr<Object>, Dependency_Graph_Error> Frequency_Trace::Builder<Object>::build() {
|
||||
auto result = Base::build(); if (!result) return std::unexpected(result.error()); auto trace = std::move(result).value();
|
||||
static_cast<typename Object::Private&>(*trace->d).bind_sources(scene, time_axis, value_axis);
|
||||
auto graph_result = scene->template edit_dependency_graph<Prepare_Data_Tag, Paint_Tag, Paint_Cache_Tag>([&](auto& prepare, auto& paint, auto& cache) {
|
||||
prepare.add_dependency(trace.get(), scene); prepare.add_dependency(trace.get(), time_axis); prepare.add_dependency(trace.get(), value_axis);
|
||||
paint.add_dependency(time_axis, trace.get()); paint.add_dependency(value_axis, trace.get());
|
||||
cache.template add_prop_dependency<&Render_Scene_2D::Prop::viewport>(trace.get(), scene);
|
||||
cache.template add_prop_dependency<&Abs_Axis::Prop::position>(trace.get(), time_axis); cache.template add_prop_dependency<&Abs_Axis::Prop::pixel_length>(trace.get(), time_axis); cache.template add_prop_dependency<&Abs_Axis::Prop::orientation>(trace.get(), time_axis);
|
||||
cache.template add_prop_dependency<&Time_Axis::Prop::visible_count>(trace.get(), time_axis); cache.template add_prop_dependency<&Time_Axis::Prop::newest_at_start>(trace.get(), time_axis); cache.template add_dependency<&Time_Axis::State::next_tick>(trace.get(), time_axis);
|
||||
cache.template add_prop_dependency<&Abs_Axis::Prop::position>(trace.get(), value_axis); cache.template add_prop_dependency<&Abs_Axis::Prop::pixel_length>(trace.get(), value_axis); cache.template add_prop_dependency<&Abs_Axis::Prop::orientation>(trace.get(), value_axis); cache.template add_prop_dependency<&Numeric_Axis::Prop::coordinate_range>(trace.get(), value_axis);
|
||||
});
|
||||
if (!graph_result) return std::unexpected(graph_result.error()); return std::move(trace);
|
||||
auto result = Base::build(); if (!result) return std::unexpected(result.error()); auto trace = std::move(result).value(); auto& private_data = static_cast<typename Object::Private&>(*trace->d); private_data.bind_sources(time_axis, value_axis);
|
||||
private_data.scene_attach = [object = trace.get()](Root* root) -> std::expected<void, Dependency_Graph_Error> { auto* scene = static_cast<Scene_Object*>(root); auto& data = static_cast<typename Object::Private&>(*object->d); data.scene = scene; auto* time_axis = data.time_axis; auto* value_axis = data.value_axis; return scene->template edit_dependency_graph<Prepare_Data_Tag, Paint_Tag, Paint_Cache_Tag>([&](auto& prepare, auto& paint, auto& cache) { prepare.add_dependency(object, scene); prepare.add_dependency(object, time_axis); prepare.add_dependency(object, value_axis); paint.add_dependency(time_axis, object); paint.add_dependency(value_axis, object); cache.template add_prop_dependency<&Render_Scene_2D::Prop::viewport>(object, scene); cache.template add_prop_dependency<&Abs_Axis::Prop::position>(object, time_axis); cache.template add_prop_dependency<&Abs_Axis::Prop::pixel_length>(object, time_axis); cache.template add_prop_dependency<&Abs_Axis::Prop::orientation>(object, time_axis); cache.template add_prop_dependency<&Time_Axis::Prop::visible_count>(object, time_axis); cache.template add_prop_dependency<&Time_Axis::Prop::newest_at_start>(object, time_axis); cache.template add_dependency<&Time_Axis::State::next_tick>(object, time_axis); cache.template add_prop_dependency<&Abs_Axis::Prop::position>(object, value_axis); cache.template add_prop_dependency<&Abs_Axis::Prop::pixel_length>(object, value_axis); cache.template add_prop_dependency<&Abs_Axis::Prop::orientation>(object, value_axis); cache.template add_prop_dependency<&Numeric_Axis::Prop::coordinate_range>(object, value_axis); }); }; return trace;
|
||||
}
|
||||
template <Attached Object>
|
||||
bool Frequency_Trace::Private::should_rebuild_prepare_graph(Object* object, const Prop& state) { return graph_partition_count != detail::curve_partition_count(state.partition_mode, state.partition_count, state.samples.size()); }
|
||||
@@ -101,5 +92,5 @@ const Frequency_Trace::Private::Dispatch& Frequency_Trace::Private::dispatch_for
|
||||
}
|
||||
template <Attached Object>
|
||||
void Frequency_Trace::Private::bind_private_crtp(Object* object) { Prev_Private::bind_private_crtp(object); dispatch = &dispatch_for<Object>(); }
|
||||
inline void Frequency_Trace::Private::bind_sources(Scene_Object* scene_value, Time_Object* time_axis_value, Value_Object* value_axis_value) { scene = scene_value; time_axis = time_axis_value; value_axis = value_axis_value; }
|
||||
inline void Frequency_Trace::Private::bind_sources(Time_Object* time_axis_value, Value_Object* value_axis_value) { time_axis = time_axis_value; value_axis = value_axis_value; }
|
||||
}
|
||||
|
||||
@@ -26,10 +26,9 @@ struct Selection_Rectangle_Overlay : Def<Selection_Rectangle_Overlay, Renderable
|
||||
template <typename Object>
|
||||
struct Builder : Prev_Builder<Object> {
|
||||
using Base = Prev_Builder<Object>;
|
||||
Builder(Scene_Object* scene, Axis_Object* horizontal_axis, Axis_Object* vertical_axis);
|
||||
Builder(Axis_Object* horizontal_axis, Axis_Object* vertical_axis);
|
||||
[[nodiscard]] std::expected<std::unique_ptr<Object>, Dependency_Graph_Error> build();
|
||||
private:
|
||||
Scene_Object* scene{}; /* 不拥有的所属 Scene。 */
|
||||
Axis_Object* horizontal_axis{}; /* 不拥有的水平坐标轴。 */
|
||||
Axis_Object* vertical_axis{}; /* 不拥有的垂直坐标轴。 */
|
||||
};
|
||||
|
||||
@@ -19,7 +19,7 @@ struct Selection_Rectangle_Overlay::Private : Prev_Private {
|
||||
const Dispatch* dispatch{}; /* 最终类型公开薄壳分派表。 */
|
||||
/* CRTP 覆盖:绑定 Paint-only、事件能力和最终 Overlay 分派表。 */
|
||||
template <Attached Object> void bind_private_crtp(Object* object);
|
||||
void bind_sources(Scene_Object* scene_value, Axis_Object* horizontal_axis_value, Axis_Object* vertical_axis_value);
|
||||
void bind_sources(Axis_Object* horizontal_axis_value, Axis_Object* vertical_axis_value);
|
||||
template <Attached Object> [[nodiscard]] static const Dispatch& dispatch_for();
|
||||
/* CRTP 覆盖:无需 Prepare 子图,直接绘制选择矩形。 */
|
||||
template <Attached Object> void paint(Object* object);
|
||||
@@ -30,31 +30,17 @@ struct Selection_Rectangle_Overlay::Private : Prev_Private {
|
||||
template <typename Object, typename Prop_Type, typename State_Type> void before_advance(Object* object, Prop_Type* pending_prop, State_Access<State_Type> pending_states, const Prop_Type* current_prop, State_Access<const State_Type> current_states);
|
||||
};
|
||||
template <typename Object>
|
||||
Selection_Rectangle_Overlay::Builder<Object>::Builder(Scene_Object* scene_value, Axis_Object* horizontal_axis_value, Axis_Object* vertical_axis_value) : Base(), scene(scene_value), horizontal_axis(horizontal_axis_value), vertical_axis(vertical_axis_value) {}
|
||||
Selection_Rectangle_Overlay::Builder<Object>::Builder(Axis_Object* horizontal_axis_value, Axis_Object* vertical_axis_value) : Base(), horizontal_axis(horizontal_axis_value), vertical_axis(vertical_axis_value) {}
|
||||
template <typename Object>
|
||||
std::expected<std::unique_ptr<Object>, Dependency_Graph_Error> Selection_Rectangle_Overlay::Builder<Object>::build() {
|
||||
auto result = Base::build();
|
||||
if (!result) return std::unexpected(result.error());
|
||||
auto overlay = std::move(result).value();
|
||||
static_cast<typename Object::Private&>(*overlay->d).bind_sources(scene, horizontal_axis, vertical_axis);
|
||||
auto graph_result = scene->template edit_dependency_graph<Prepare_Data_Tag, Paint_Tag, Paint_Cache_Tag>([&](auto& prepare, auto& paint, auto& cache) {
|
||||
prepare.add_dependency(overlay.get(), scene);
|
||||
prepare.add_dependency(overlay.get(), horizontal_axis);
|
||||
prepare.add_dependency(overlay.get(), vertical_axis);
|
||||
paint.add_dependency(horizontal_axis, overlay.get());
|
||||
paint.add_dependency(vertical_axis, overlay.get());
|
||||
cache.template add_prop_dependency<&Render_Scene_2D::Prop::viewport>(overlay.get(), scene);
|
||||
cache.template add_prop_dependency<&Abs_Axis::Prop::position>(overlay.get(), horizontal_axis);
|
||||
cache.template add_prop_dependency<&Abs_Axis::Prop::pixel_length>(overlay.get(), horizontal_axis);
|
||||
cache.template add_prop_dependency<&Abs_Axis::Prop::orientation>(overlay.get(), horizontal_axis);
|
||||
cache.template add_prop_dependency<&Numeric_Axis::Prop::coordinate_range>(overlay.get(), horizontal_axis);
|
||||
cache.template add_prop_dependency<&Abs_Axis::Prop::position>(overlay.get(), vertical_axis);
|
||||
cache.template add_prop_dependency<&Abs_Axis::Prop::pixel_length>(overlay.get(), vertical_axis);
|
||||
cache.template add_prop_dependency<&Abs_Axis::Prop::orientation>(overlay.get(), vertical_axis);
|
||||
cache.template add_prop_dependency<&Numeric_Axis::Prop::coordinate_range>(overlay.get(), vertical_axis);
|
||||
});
|
||||
if (!graph_result) return std::unexpected(graph_result.error());
|
||||
return std::move(overlay);
|
||||
auto& private_data = static_cast<typename Object::Private&>(*overlay->d); private_data.bind_sources(horizontal_axis, vertical_axis);
|
||||
private_data.scene_attach = [object = overlay.get()](Root* root) -> std::expected<void, Dependency_Graph_Error> {
|
||||
auto* scene = static_cast<Scene_Object*>(root); auto& data = static_cast<typename Object::Private&>(*object->d); data.scene = scene; auto* horizontal_axis = data.horizontal_axis; auto* vertical_axis = data.vertical_axis;
|
||||
return scene->template edit_dependency_graph<Prepare_Data_Tag, Paint_Tag, Paint_Cache_Tag>([&](auto& prepare, auto& paint, auto& cache) { prepare.add_dependency(object, scene); prepare.add_dependency(object, horizontal_axis); prepare.add_dependency(object, vertical_axis); paint.add_dependency(horizontal_axis, object); paint.add_dependency(vertical_axis, object); cache.template add_prop_dependency<&Render_Scene_2D::Prop::viewport>(object, scene); cache.template add_prop_dependency<&Abs_Axis::Prop::position>(object, horizontal_axis); cache.template add_prop_dependency<&Abs_Axis::Prop::pixel_length>(object, horizontal_axis); cache.template add_prop_dependency<&Abs_Axis::Prop::orientation>(object, horizontal_axis); cache.template add_prop_dependency<&Numeric_Axis::Prop::coordinate_range>(object, horizontal_axis); cache.template add_prop_dependency<&Abs_Axis::Prop::position>(object, vertical_axis); cache.template add_prop_dependency<&Abs_Axis::Prop::pixel_length>(object, vertical_axis); cache.template add_prop_dependency<&Abs_Axis::Prop::orientation>(object, vertical_axis); cache.template add_prop_dependency<&Numeric_Axis::Prop::coordinate_range>(object, vertical_axis); });
|
||||
}; return overlay;
|
||||
}
|
||||
template <Attached Object>
|
||||
void Selection_Rectangle_Overlay::Private::paint(Object* object) {
|
||||
@@ -101,5 +87,5 @@ const Selection_Rectangle_Overlay::Private::Dispatch& Selection_Rectangle_Overla
|
||||
}
|
||||
template <Attached Object>
|
||||
void Selection_Rectangle_Overlay::Private::bind_private_crtp(Object* object) { Prev_Private::bind_private_crtp(object); dispatch = &dispatch_for<Object>(); }
|
||||
inline void Selection_Rectangle_Overlay::Private::bind_sources(Scene_Object* scene_value, Axis_Object* horizontal_axis_value, Axis_Object* vertical_axis_value) { scene = scene_value; horizontal_axis = horizontal_axis_value; vertical_axis = vertical_axis_value; }
|
||||
inline void Selection_Rectangle_Overlay::Private::bind_sources(Axis_Object* horizontal_axis_value, Axis_Object* vertical_axis_value) { horizontal_axis = horizontal_axis_value; vertical_axis = vertical_axis_value; }
|
||||
}
|
||||
|
||||
@@ -65,10 +65,9 @@ struct Spectrum : Def<Spectrum, Renderable_2D<Renderable_2D_Cache::enabled>, Tag
|
||||
template <typename Object>
|
||||
struct Builder : Prev_Builder<Object> {
|
||||
using Base = Prev_Builder<Object>;
|
||||
Builder(Scene_Object* scene, Frequency_Object* frequency_axis, Power_Object* power_axis);
|
||||
Builder(Frequency_Object* frequency_axis, Power_Object* power_axis);
|
||||
[[nodiscard]] std::expected<std::unique_ptr<Object>, Dependency_Graph_Error> build();
|
||||
private:
|
||||
Scene_Object* scene{}; /* 不拥有的所属二维 Scene;生命周期必须覆盖 Spectrum。 */
|
||||
Frequency_Object* frequency_axis{}; /* 不拥有的频率轴;生命周期必须覆盖 Spectrum。 */
|
||||
Power_Object* power_axis{}; /* 不拥有的功率轴;生命周期必须覆盖 Spectrum。 */
|
||||
};
|
||||
|
||||
@@ -67,7 +67,7 @@ struct Spectrum::Private : Prev_Private {
|
||||
/* CRTP 覆盖:绑定 Renderable 机制和 Spectrum 公开薄壳分派;派生 Private 必须先调用此实现。 */
|
||||
template <Attached Object> void bind_private_crtp(Object* object);
|
||||
/* Builder 内部绑定 Scene 与两根轴;三个来源都必须比 Spectrum 生命周期更长。 */
|
||||
void bind_render_sources(Scene_Object* scene_value, Frequency_Object* frequency_axis_value, Power_Object* power_axis_value);
|
||||
void bind_render_sources(Frequency_Object* frequency_axis_value, Power_Object* power_axis_value);
|
||||
template <Attached Object> [[nodiscard]] static const Dispatch& dispatch_for();
|
||||
template <Attached Object> void update_samples(Object* object, std::span<const Spectrum_Power> values);
|
||||
template <Attached Object> void add_marker(Object* object, Spectrum_Frequency frequency);
|
||||
@@ -95,31 +95,38 @@ struct Spectrum::Private : Prev_Private {
|
||||
[[nodiscard]] static std::expected<Spectrum_Power, Power_At_Result> power_at(const Prop& state, const Spectrum_Frame& frame, Spectrum_Frequency frequency);
|
||||
};
|
||||
template <typename Object>
|
||||
Spectrum::Builder<Object>::Builder(Scene_Object* scene_value, Frequency_Object* frequency_axis_value, Power_Object* power_axis_value) : Base(), scene(scene_value), frequency_axis(frequency_axis_value), power_axis(power_axis_value) {}
|
||||
Spectrum::Builder<Object>::Builder(Frequency_Object* frequency_axis_value, Power_Object* power_axis_value) : Base(), frequency_axis(frequency_axis_value), power_axis(power_axis_value) {}
|
||||
template <typename Object>
|
||||
std::expected<std::unique_ptr<Object>, Dependency_Graph_Error> Spectrum::Builder<Object>::build() {
|
||||
auto result = Base::build();
|
||||
if (!result) return std::unexpected(result.error());
|
||||
auto spectrum = std::move(result).value();
|
||||
static_cast<typename Object::Private&>(*spectrum->d).bind_render_sources(scene, frequency_axis, power_axis);
|
||||
auto dependency_result = scene->template edit_dependency_graph<Prepare_Data_Tag, Paint_Tag, Paint_Cache_Tag>([&](auto& prepare, auto& paint, auto& cache) {
|
||||
prepare.add_dependency(spectrum.get(), scene);
|
||||
prepare.add_dependency(spectrum.get(), frequency_axis);
|
||||
prepare.add_dependency(spectrum.get(), power_axis);
|
||||
paint.add_dependency(frequency_axis, spectrum.get());
|
||||
paint.add_dependency(power_axis, spectrum.get());
|
||||
cache.template add_prop_dependency<&Render_Scene_2D::Prop::viewport>(spectrum.get(), scene);
|
||||
cache.template add_prop_dependency<&Abs_Axis::Prop::position>(spectrum.get(), frequency_axis);
|
||||
cache.template add_prop_dependency<&Abs_Axis::Prop::pixel_length>(spectrum.get(), frequency_axis);
|
||||
cache.template add_prop_dependency<&Abs_Axis::Prop::orientation>(spectrum.get(), frequency_axis);
|
||||
cache.template add_prop_dependency<&Numeric_Axis::Prop::coordinate_range>(spectrum.get(), frequency_axis);
|
||||
cache.template add_prop_dependency<&Abs_Axis::Prop::position>(spectrum.get(), power_axis);
|
||||
cache.template add_prop_dependency<&Abs_Axis::Prop::pixel_length>(spectrum.get(), power_axis);
|
||||
cache.template add_prop_dependency<&Abs_Axis::Prop::orientation>(spectrum.get(), power_axis);
|
||||
cache.template add_prop_dependency<&Numeric_Axis::Prop::coordinate_range>(spectrum.get(), power_axis);
|
||||
});
|
||||
if (!dependency_result) return std::unexpected(dependency_result.error());
|
||||
return std::move(spectrum);
|
||||
auto& private_data = static_cast<typename Object::Private&>(*spectrum->d);
|
||||
private_data.bind_render_sources(frequency_axis, power_axis);
|
||||
private_data.scene_attach = [object = spectrum.get()](Root* root) -> std::expected<void, Dependency_Graph_Error> {
|
||||
auto* scene = static_cast<Scene_Object*>(root);
|
||||
auto& data = static_cast<typename Object::Private&>(*object->d);
|
||||
data.scene = scene;
|
||||
auto* frequency_axis = data.frequency_axis;
|
||||
auto* power_axis = data.power_axis;
|
||||
return scene->template edit_dependency_graph<Prepare_Data_Tag, Paint_Tag, Paint_Cache_Tag>([&](auto& prepare, auto& paint, auto& cache) {
|
||||
prepare.add_dependency(object, scene);
|
||||
prepare.add_dependency(object, frequency_axis);
|
||||
prepare.add_dependency(object, power_axis);
|
||||
paint.add_dependency(frequency_axis, object);
|
||||
paint.add_dependency(power_axis, object);
|
||||
cache.template add_prop_dependency<&Render_Scene_2D::Prop::viewport>(object, scene);
|
||||
cache.template add_prop_dependency<&Abs_Axis::Prop::position>(object, frequency_axis);
|
||||
cache.template add_prop_dependency<&Abs_Axis::Prop::pixel_length>(object, frequency_axis);
|
||||
cache.template add_prop_dependency<&Abs_Axis::Prop::orientation>(object, frequency_axis);
|
||||
cache.template add_prop_dependency<&Numeric_Axis::Prop::coordinate_range>(object, frequency_axis);
|
||||
cache.template add_prop_dependency<&Abs_Axis::Prop::position>(object, power_axis);
|
||||
cache.template add_prop_dependency<&Abs_Axis::Prop::pixel_length>(object, power_axis);
|
||||
cache.template add_prop_dependency<&Abs_Axis::Prop::orientation>(object, power_axis);
|
||||
cache.template add_prop_dependency<&Numeric_Axis::Prop::coordinate_range>(object, power_axis);
|
||||
});
|
||||
};
|
||||
return spectrum;
|
||||
}
|
||||
template <typename Values>
|
||||
void Spectrum::update_samples(const Values& values) {
|
||||
@@ -353,8 +360,7 @@ void Spectrum::Private::bind_private_crtp(Object* object) {
|
||||
Prev_Private::bind_private_crtp(object);
|
||||
dispatch = &Private::dispatch_for<Object>();
|
||||
}
|
||||
inline void Spectrum::Private::bind_render_sources(Scene_Object* scene_value, Frequency_Object* frequency_axis_value, Power_Object* power_axis_value) {
|
||||
scene = scene_value;
|
||||
inline void Spectrum::Private::bind_render_sources(Frequency_Object* frequency_axis_value, Power_Object* power_axis_value) {
|
||||
frequency_axis = frequency_axis_value;
|
||||
power_axis = power_axis_value;
|
||||
}
|
||||
|
||||
@@ -36,10 +36,9 @@ struct Sweep_Spectrum : Def<Sweep_Spectrum, Renderable_2D<Renderable_2D_Cache::e
|
||||
template <typename Object>
|
||||
struct Builder : Prev_Builder<Object> {
|
||||
using Base = Prev_Builder<Object>;
|
||||
Builder(Scene_Object* scene, Frequency_Object* frequency_axis, Power_Object* power_axis);
|
||||
Builder(Frequency_Object* frequency_axis, Power_Object* power_axis);
|
||||
[[nodiscard]] std::expected<std::unique_ptr<Object>, Dependency_Graph_Error> build();
|
||||
private:
|
||||
Scene_Object* scene{}; /* 不拥有的所属 Scene。 */
|
||||
Frequency_Object* frequency_axis{}; /* 不拥有的频率轴。 */
|
||||
Power_Object* power_axis{}; /* 不拥有的功率轴。 */
|
||||
};
|
||||
|
||||
@@ -26,7 +26,7 @@ struct Sweep_Spectrum::Private : Prev_Private {
|
||||
const Dispatch* dispatch{}; /* 最终类型公开薄壳分派表。 */
|
||||
/* CRTP 覆盖:绑定 Renderable 能力和最终 Sweep_Spectrum 分派表。 */
|
||||
template <Attached Object> void bind_private_crtp(Object* object);
|
||||
void bind_sources(Scene_Object* scene_value, Frequency_Object* frequency_axis_value, Power_Object* power_axis_value);
|
||||
void bind_sources(Frequency_Object* frequency_axis_value, Power_Object* power_axis_value);
|
||||
template <Attached Object> [[nodiscard]] static const Dispatch& dispatch_for();
|
||||
/* CRTP 覆盖:按扫描点规模构建分块 Prepare 子图。 */
|
||||
template <Attached Object> [[nodiscard]] tf::Taskflow build_prepare_graph(Object* object, const Prop& state);
|
||||
@@ -41,12 +41,11 @@ struct Sweep_Spectrum::Private : Prev_Private {
|
||||
template <typename Object, typename Prop_Type, typename State_Type> void before_advance(Object* object, Prop_Type* pending_prop, State_Access<State_Type> pending_states, const Prop_Type* current_prop, State_Access<const State_Type> current_states);
|
||||
};
|
||||
template <typename Object>
|
||||
Sweep_Spectrum::Builder<Object>::Builder(Scene_Object* scene_value, Frequency_Object* frequency_axis_value, Power_Object* power_axis_value) : Base(), scene(scene_value), frequency_axis(frequency_axis_value), power_axis(power_axis_value) {}
|
||||
Sweep_Spectrum::Builder<Object>::Builder(Frequency_Object* frequency_axis_value, Power_Object* power_axis_value) : Base(), frequency_axis(frequency_axis_value), power_axis(power_axis_value) {}
|
||||
template <typename Object>
|
||||
std::expected<std::unique_ptr<Object>, Dependency_Graph_Error> Sweep_Spectrum::Builder<Object>::build() {
|
||||
auto result = Base::build(); if (!result) return std::unexpected(result.error()); auto sweep = std::move(result).value(); static_cast<typename Object::Private&>(*sweep->d).bind_sources(scene, frequency_axis, power_axis);
|
||||
auto graph_result = scene->template edit_dependency_graph<Prepare_Data_Tag, Paint_Tag, Paint_Cache_Tag>([&](auto& prepare, auto& paint, auto& cache) { prepare.add_dependency(sweep.get(), scene); prepare.add_dependency(sweep.get(), frequency_axis); prepare.add_dependency(sweep.get(), power_axis); paint.add_dependency(frequency_axis, sweep.get()); paint.add_dependency(power_axis, sweep.get()); cache.template add_prop_dependency<&Render_Scene_2D::Prop::viewport>(sweep.get(), scene); cache.template add_prop_dependency<&Abs_Axis::Prop::position>(sweep.get(), frequency_axis); cache.template add_prop_dependency<&Abs_Axis::Prop::pixel_length>(sweep.get(), frequency_axis); cache.template add_prop_dependency<&Abs_Axis::Prop::orientation>(sweep.get(), frequency_axis); cache.template add_prop_dependency<&Numeric_Axis::Prop::coordinate_range>(sweep.get(), frequency_axis); cache.template add_prop_dependency<&Abs_Axis::Prop::position>(sweep.get(), power_axis); cache.template add_prop_dependency<&Abs_Axis::Prop::pixel_length>(sweep.get(), power_axis); cache.template add_prop_dependency<&Abs_Axis::Prop::orientation>(sweep.get(), power_axis); cache.template add_prop_dependency<&Numeric_Axis::Prop::coordinate_range>(sweep.get(), power_axis); });
|
||||
if (!graph_result) return std::unexpected(graph_result.error()); return std::move(sweep);
|
||||
auto result = Base::build(); if (!result) return std::unexpected(result.error()); auto sweep = std::move(result).value(); auto& private_data = static_cast<typename Object::Private&>(*sweep->d); private_data.bind_sources(frequency_axis, power_axis);
|
||||
private_data.scene_attach = [object = sweep.get()](Root* root) -> std::expected<void, Dependency_Graph_Error> { auto* scene = static_cast<Scene_Object*>(root); auto& data = static_cast<typename Object::Private&>(*object->d); data.scene = scene; auto* frequency_axis = data.frequency_axis; auto* power_axis = data.power_axis; return scene->template edit_dependency_graph<Prepare_Data_Tag, Paint_Tag, Paint_Cache_Tag>([&](auto& prepare, auto& paint, auto& cache) { prepare.add_dependency(object, scene); prepare.add_dependency(object, frequency_axis); prepare.add_dependency(object, power_axis); paint.add_dependency(frequency_axis, object); paint.add_dependency(power_axis, object); cache.template add_prop_dependency<&Render_Scene_2D::Prop::viewport>(object, scene); cache.template add_prop_dependency<&Abs_Axis::Prop::position>(object, frequency_axis); cache.template add_prop_dependency<&Abs_Axis::Prop::pixel_length>(object, frequency_axis); cache.template add_prop_dependency<&Abs_Axis::Prop::orientation>(object, frequency_axis); cache.template add_prop_dependency<&Numeric_Axis::Prop::coordinate_range>(object, frequency_axis); cache.template add_prop_dependency<&Abs_Axis::Prop::position>(object, power_axis); cache.template add_prop_dependency<&Abs_Axis::Prop::pixel_length>(object, power_axis); cache.template add_prop_dependency<&Abs_Axis::Prop::orientation>(object, power_axis); cache.template add_prop_dependency<&Numeric_Axis::Prop::coordinate_range>(object, power_axis); }); }; return sweep;
|
||||
}
|
||||
template <typename Values> void Sweep_Spectrum::append_block(const Values& values) { append_block(std::span<const Plot_Value>(std::data(values), std::size(values))); }
|
||||
template <Attached Object>
|
||||
@@ -82,5 +81,5 @@ const Sweep_Spectrum::Private::Dispatch& Sweep_Spectrum::Private::dispatch_for()
|
||||
}; return value;
|
||||
}
|
||||
template <Attached Object> void Sweep_Spectrum::Private::bind_private_crtp(Object* object) { Prev_Private::bind_private_crtp(object); dispatch = &dispatch_for<Object>(); }
|
||||
inline void Sweep_Spectrum::Private::bind_sources(Scene_Object* scene_value, Frequency_Object* frequency_axis_value, Power_Object* power_axis_value) { scene = scene_value; frequency_axis = frequency_axis_value; power_axis = power_axis_value; }
|
||||
inline void Sweep_Spectrum::Private::bind_sources(Frequency_Object* frequency_axis_value, Power_Object* power_axis_value) { frequency_axis = frequency_axis_value; power_axis = power_axis_value; }
|
||||
}
|
||||
|
||||
@@ -38,10 +38,9 @@ struct Waterfall : Def<Waterfall, Renderable_2D<Renderable_2D_Cache::enabled>> {
|
||||
struct Private;
|
||||
template <typename Object> struct Builder : Prev_Builder<Object> {
|
||||
using Base = Prev_Builder<Object>;
|
||||
Builder(Scene_Object* scene, Frequency_Object* frequency_axis, Time_Object* time_axis);
|
||||
Builder(Frequency_Object* frequency_axis, Time_Object* time_axis);
|
||||
[[nodiscard]] std::expected<std::unique_ptr<Object>, Dependency_Graph_Error> build();
|
||||
private:
|
||||
Scene_Object* scene{}; /* 不拥有的所属 Scene;生命周期必须覆盖 Waterfall。 */
|
||||
Frequency_Object* frequency_axis{}; /* 不拥有的频率轴;生命周期必须覆盖 Waterfall。 */
|
||||
Time_Object* time_axis{}; /* 不拥有的时间轴;生命周期必须覆盖 Waterfall。 */
|
||||
};
|
||||
|
||||
@@ -33,7 +33,7 @@ struct Waterfall::Private : Prev_Private {
|
||||
const Dispatch* dispatch{}; /* 最终类型的公开薄壳分派表。 */
|
||||
/* CRTP 覆盖:绑定 Renderable、事件能力和最终 Waterfall 分派表。 */
|
||||
template <Attached Object> void bind_private_crtp(Object* object);
|
||||
void bind_sources(Scene_Object* scene_value, Frequency_Object* frequency_axis_value, Time_Object* time_axis_value);
|
||||
void bind_sources(Frequency_Object* frequency_axis_value, Time_Object* time_axis_value);
|
||||
template <Attached Object> [[nodiscard]] static const Dispatch& dispatch_for();
|
||||
/* CRTP 覆盖:按当前色块工作量构建分块 Prepare 子图。 */
|
||||
template <Attached Object> [[nodiscard]] tf::Taskflow build_prepare_graph(Object* object, const Prop& state);
|
||||
@@ -48,9 +48,16 @@ struct Waterfall::Private : Prev_Private {
|
||||
template <typename Object, typename Owner, typename Member, typename Prop_Type> void after_prop_set(Object* object, Member Owner::* member, Prop_Access<Prop_Type> states);
|
||||
template <typename Object, typename Prop_Type, typename State_Type> void before_advance(Object* object, Prop_Type* pending_prop, State_Access<State_Type> pending_states, const Prop_Type* current_prop, State_Access<const State_Type> current_states);
|
||||
};
|
||||
template <typename Object> Waterfall::Builder<Object>::Builder(Scene_Object* scene_value, Frequency_Object* frequency_axis_value, Time_Object* time_axis_value) : Base(), scene(scene_value), frequency_axis(frequency_axis_value), time_axis(time_axis_value) {}
|
||||
template <typename Object> Waterfall::Builder<Object>::Builder(Frequency_Object* frequency_axis_value, Time_Object* time_axis_value) : Base(), frequency_axis(frequency_axis_value), time_axis(time_axis_value) {}
|
||||
template <typename Object>
|
||||
std::expected<std::unique_ptr<Object>, Dependency_Graph_Error> Waterfall::Builder<Object>::build() { auto result = Base::build(); if (!result) return std::unexpected(result.error()); auto plot = std::move(result).value(); static_cast<typename Object::Private&>(*plot->d).bind_sources(scene, frequency_axis, time_axis); auto graph_result = scene->template edit_dependency_graph<Prepare_Data_Tag, Paint_Tag, Paint_Cache_Tag>([&](auto& prepare, auto& paint, auto& cache) { prepare.add_dependency(plot.get(), scene); prepare.add_dependency(plot.get(), frequency_axis); prepare.add_dependency(plot.get(), time_axis); paint.add_dependency(frequency_axis, plot.get()); paint.add_dependency(time_axis, plot.get()); cache.template add_prop_dependency<&Render_Scene_2D::Prop::viewport>(plot.get(), scene); cache.template add_prop_dependency<&Abs_Axis::Prop::position>(plot.get(), frequency_axis); cache.template add_prop_dependency<&Abs_Axis::Prop::pixel_length>(plot.get(), frequency_axis); cache.template add_prop_dependency<&Abs_Axis::Prop::orientation>(plot.get(), frequency_axis); cache.template add_prop_dependency<&Numeric_Axis::Prop::coordinate_range>(plot.get(), frequency_axis); cache.template add_prop_dependency<&Abs_Axis::Prop::position>(plot.get(), time_axis); cache.template add_prop_dependency<&Abs_Axis::Prop::pixel_length>(plot.get(), time_axis); cache.template add_prop_dependency<&Abs_Axis::Prop::orientation>(plot.get(), time_axis); cache.template add_prop_dependency<&Time_Axis::Prop::visible_count>(plot.get(), time_axis); cache.template add_prop_dependency<&Time_Axis::Prop::newest_at_start>(plot.get(), time_axis); cache.template add_dependency<&Time_Axis::State::next_tick>(plot.get(), time_axis); }); if (!graph_result) return std::unexpected(graph_result.error()); return std::move(plot); }
|
||||
std::expected<std::unique_ptr<Object>, Dependency_Graph_Error> Waterfall::Builder<Object>::build() {
|
||||
auto result = Base::build(); if (!result) return std::unexpected(result.error()); auto plot = std::move(result).value();
|
||||
auto& private_data = static_cast<typename Object::Private&>(*plot->d); private_data.bind_sources(frequency_axis, time_axis);
|
||||
private_data.scene_attach = [object = plot.get()](Root* root) -> std::expected<void, Dependency_Graph_Error> {
|
||||
auto* scene = static_cast<Scene_Object*>(root); auto& data = static_cast<typename Object::Private&>(*object->d); data.scene = scene; auto* frequency_axis = data.frequency_axis; auto* time_axis = data.time_axis;
|
||||
return scene->template edit_dependency_graph<Prepare_Data_Tag, Paint_Tag, Paint_Cache_Tag>([&](auto& prepare, auto& paint, auto& cache) { prepare.add_dependency(object, scene); prepare.add_dependency(object, frequency_axis); prepare.add_dependency(object, time_axis); paint.add_dependency(frequency_axis, object); paint.add_dependency(time_axis, object); cache.template add_prop_dependency<&Render_Scene_2D::Prop::viewport>(object, scene); cache.template add_prop_dependency<&Abs_Axis::Prop::position>(object, frequency_axis); cache.template add_prop_dependency<&Abs_Axis::Prop::pixel_length>(object, frequency_axis); cache.template add_prop_dependency<&Abs_Axis::Prop::orientation>(object, frequency_axis); cache.template add_prop_dependency<&Numeric_Axis::Prop::coordinate_range>(object, frequency_axis); cache.template add_prop_dependency<&Abs_Axis::Prop::position>(object, time_axis); cache.template add_prop_dependency<&Abs_Axis::Prop::pixel_length>(object, time_axis); cache.template add_prop_dependency<&Abs_Axis::Prop::orientation>(object, time_axis); cache.template add_prop_dependency<&Time_Axis::Prop::visible_count>(object, time_axis); cache.template add_prop_dependency<&Time_Axis::Prop::newest_at_start>(object, time_axis); cache.template add_dependency<&Time_Axis::State::next_tick>(object, time_axis); });
|
||||
}; return plot;
|
||||
}
|
||||
template <typename Values> void Waterfall::append_row(Plot_Time_Tick tick, const Values& values) { append_row(tick, std::span<const Plot_Value>(std::data(values), std::size(values))); }
|
||||
template <typename Values> void Waterfall::append_row(Time_Of_Day time, const Values& values) { append_row(time, std::span<const Plot_Value>(std::data(values), std::size(values))); }
|
||||
template <Attached Object> bool Waterfall::Private::should_rebuild_prepare_graph(Object*, const Prop& state) { const std::size_t cells = state.rows.size() * (state.frequency_bin_count ? state.frequency_bin_count : state.rows.empty() ? 1 : state.rows.back().values.size()); return graph_partition_count != detail::curve_partition_count(state.partition_mode, state.partition_count, cells); }
|
||||
@@ -67,5 +74,5 @@ template <typename Object, typename Prop_Type, typename State_Type> void Waterfa
|
||||
template <Attached Object>
|
||||
const Waterfall::Private::Dispatch& Waterfall::Private::dispatch_for() { static const Dispatch value{[](Root* root, Plot_Time_Tick tick, std::span<const Plot_Value> values) { auto* object = static_cast<Object*>(root); auto& data = static_cast<typename Object::Private&>(*object->d); const std::size_t row_limit = static_cast<std::size_t>(std::max<Axis_Visible_Count>(2, data.time_axis->template read_prop<Time_Axis::Base_Tag>().visible_count)); object->template update_prop<&Prop::rows>([=](Prop_Access<typename Object::Prop> props) { auto& state = props.template get<Waterfall::Base_Tag>(); state.rows.push_back({tick, {values.begin(), values.end()}}); while (state.rows.size() > row_limit) state.rows.erase(state.rows.begin()); }); }, [](Root* root, Time_Of_Day time, std::span<const Plot_Value> values) { auto* object = static_cast<Object*>(root); auto& data = static_cast<typename Object::Private&>(*object->d); data.dispatch->append(root, data.time_axis->append_time(time), values); }, [](const Root* root) { return static_cast<const Object*>(root)->template read_prop<Waterfall::Base_Tag>().rows.size(); }, [](const Root* root) { const auto& rows = static_cast<const Object*>(root)->template read_prop<Waterfall::Base_Tag>().rows; std::size_t count{}; for (const auto& row : rows) count += row.values.size(); return count; }, [](const Root* root) { const auto& data = static_cast<const typename Object::Private&>(*static_cast<const Object*>(root)->d); return data.prepared.valid ? data.prepared.pixels.size() : 0; }}; return value; }
|
||||
template <Attached Object> void Waterfall::Private::bind_private_crtp(Object* object) { Prev_Private::bind_private_crtp(object); dispatch = &dispatch_for<Object>(); }
|
||||
inline void Waterfall::Private::bind_sources(Scene_Object* scene_value, Frequency_Object* frequency_axis_value, Time_Object* time_axis_value) { scene = scene_value; frequency_axis = frequency_axis_value; time_axis = time_axis_value; }
|
||||
inline void Waterfall::Private::bind_sources(Frequency_Object* frequency_axis_value, Time_Object* time_axis_value) { frequency_axis = frequency_axis_value; time_axis = time_axis_value; }
|
||||
}
|
||||
|
||||
@@ -22,6 +22,17 @@ struct Render_Scene_2D : Def<Render_Scene_2D, Scene,
|
||||
};
|
||||
/* 完整声明、合成顺序和 CRTP 分派见 Render_Scene_2D.ipp。 */
|
||||
struct Private;
|
||||
template <typename Object>
|
||||
struct Builder : Prev_Builder<Object> {
|
||||
using Base = Prev_Builder<Object>;
|
||||
Builder();
|
||||
template <Attached Renderable_Object>
|
||||
requires std::derived_from<Renderable_Object, Renderable_2D_Base>
|
||||
Builder& add_renderable(Renderable_Object* renderable);
|
||||
[[nodiscard]] std::expected<std::unique_ptr<Object>, Dependency_Graph_Error> build();
|
||||
private:
|
||||
std::vector<std::function<std::expected<void, Dependency_Graph_Error>(Object*)>> attachments{}; /* 仅在 build 期间绑定已构造 Renderable。 */
|
||||
};
|
||||
using Frame_Callback = std::function<void(Image_View)>;
|
||||
/* 合成一帧;执行期间的重复调用合并为一次后继帧。 */
|
||||
void render();
|
||||
|
||||
@@ -4,6 +4,32 @@
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
namespace aethera::render_2d {
|
||||
template <typename Object>
|
||||
Render_Scene_2D::Builder<Object>::Builder() : Base() {}
|
||||
template <typename Object>
|
||||
template <Attached Renderable_Object>
|
||||
requires std::derived_from<Renderable_Object, Renderable_2D_Base>
|
||||
Render_Scene_2D::Builder<Object>& Render_Scene_2D::Builder<Object>::add_renderable(Renderable_Object* renderable) {
|
||||
attachments.emplace_back([renderable](Object* scene) {
|
||||
auto& data = Base::private_access(renderable).template get<Renderable_2D_Base::Base_Tag>();
|
||||
if (!data.scene_attach)
|
||||
throw std::logic_error("2D renderable has no scene attachment contract");
|
||||
auto attach = std::move(data.scene_attach);
|
||||
return attach(scene);
|
||||
});
|
||||
return *this;
|
||||
}
|
||||
template <typename Object>
|
||||
std::expected<std::unique_ptr<Object>, Dependency_Graph_Error> Render_Scene_2D::Builder<Object>::build() {
|
||||
auto result = Base::build();
|
||||
if (!result) return std::unexpected(result.error());
|
||||
auto scene = std::move(result).value();
|
||||
for (auto& attach : attachments) {
|
||||
auto attach_result = attach(scene.get());
|
||||
if (!attach_result) return std::unexpected(attach_result.error());
|
||||
}
|
||||
return scene;
|
||||
}
|
||||
struct Render_Scene_2D::Private : Prev_Private {
|
||||
using Render_Run = void (*)(Root*);
|
||||
using Callback_Run = void (*)(Root*, Frame_Callback);
|
||||
|
||||
Reference in New Issue
Block a user