加入3D
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
#include <visual_common.hpp>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
@@ -77,20 +78,6 @@ struct Rect_F {
|
||||
}
|
||||
bool operator==(const Rect_F&) const = default;
|
||||
};
|
||||
/* 非预乘 RGBA 颜色。 */
|
||||
struct Color {
|
||||
std::uint8_t red{}; /* 红色通道。 */
|
||||
std::uint8_t green{}; /* 绿色通道。 */
|
||||
std::uint8_t blue{}; /* 蓝色通道。 */
|
||||
std::uint8_t alpha{255}; /* 不透明度通道。 */
|
||||
[[nodiscard]] static constexpr Color transparent() noexcept { return {0, 0, 0, 0}; }
|
||||
[[nodiscard]] static constexpr Color black() noexcept { return {0, 0, 0, 255}; }
|
||||
[[nodiscard]] static constexpr Color white() noexcept { return {255, 255, 255, 255}; }
|
||||
[[nodiscard]] static constexpr Color red_color() noexcept { return {255, 0, 0, 255}; }
|
||||
[[nodiscard]] static constexpr Color green_color() noexcept { return {0, 255, 0, 255}; }
|
||||
[[nodiscard]] static constexpr Color yellow() noexcept { return {255, 255, 0, 255}; }
|
||||
bool operator==(const Color&) const = default;
|
||||
};
|
||||
using Pixel = std::uint32_t;
|
||||
[[nodiscard]] constexpr Pixel premultiply(Color color) noexcept {
|
||||
const auto red = static_cast<std::uint32_t>((color.red * color.alpha + 127) / 255);
|
||||
@@ -141,14 +128,6 @@ struct Number_Locale {
|
||||
char decimal_point{'.'}; /* 替换默认小数点的字符。 */
|
||||
bool operator==(const Number_Locale&) const = default;
|
||||
};
|
||||
/* 一天内的时间值。 */
|
||||
struct Time_Of_Day {
|
||||
std::int64_t milliseconds{-1}; /* 自当天零点起的毫秒数;负值表示无效。 */
|
||||
[[nodiscard]] bool valid() const noexcept {
|
||||
return milliseconds >= 0 && milliseconds < 24LL * 60LL * 60LL * 1000LL;
|
||||
}
|
||||
bool operator==(const Time_Of_Day&) const = default;
|
||||
};
|
||||
enum class Image_Interpolation_Mode : std::uint8_t { nearest, bilinear, bicubic };
|
||||
enum class Line_Interpolation_Mode : std::uint8_t {
|
||||
nearest_sample,
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
#include "common/Curve_Plot.hpp"
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <numbers>
|
||||
namespace aethera::render_2d {
|
||||
struct Constellation_Diagram::Private : Prev_Private {
|
||||
@@ -33,19 +32,17 @@ struct Constellation_Diagram::Private : Prev_Private {
|
||||
/* CRTP 覆盖:本类状态写入后标记 Prepare 数据失效。 */
|
||||
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);
|
||||
[[nodiscard]] static Plot_Duration_Milliseconds now_ms();
|
||||
};
|
||||
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>
|
||||
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>([&](auto& prepare, auto& paint) { prepare.add(i_axis); prepare.add(q_axis); prepare.add(plot.get()); prepare.template add_prop_dependency<Render_Scene_2D::Base_Tag>(plot.get(), scene); prepare.template add_prop_dependency<Abs_Axis::Base_Tag>(plot.get(), i_axis); prepare.template add_prop_dependency<Numeric_Axis::Base_Tag>(plot.get(), i_axis); prepare.template add_prop_dependency<Abs_Axis::Base_Tag>(plot.get(), q_axis); prepare.template add_prop_dependency<Numeric_Axis::Base_Tag>(plot.get(), q_axis); paint.add(i_axis); paint.add(q_axis); paint.add(plot.get()); }); if (!graph_result) return std::unexpected(graph_result.error()); return std::move(plot); }
|
||||
inline Plot_Duration_Milliseconds Constellation_Diagram::Private::now_ms() { return static_cast<Plot_Duration_Milliseconds>(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now().time_since_epoch()).count()); }
|
||||
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 = now_ms(); 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>(); }
|
||||
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 = object->template pending_buffer<Color_Cache>(); cache.ensure_size(prepared.canvas); cache.clear(); 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}); }
|
||||
template <typename Object, typename Owner, typename Member, typename Prop_Type> void Constellation_Diagram::Private::after_prop_set(Object* object, Member Owner::*, Prop_Access<Prop_Type>) { if constexpr (std::same_as<Owner, Prop>) object->template mark_dirty<Prepare_Data_Tag>(); }
|
||||
template <typename Object, typename Prop_Type, typename State_Type> void Constellation_Diagram::Private::before_advance(Object*, Prop_Type*, State_Access<State_Type> pending_states, const Prop_Type* current_prop, State_Access<const State_Type>) { pending_states.template get<Constellation_Diagram::Base_Tag>().point_count = static_cast<const Prop&>(*current_prop).points.size(); }
|
||||
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 = Private::now_ms(); 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; }
|
||||
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; }
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ using Plot_Coordinate = double;
|
||||
using Plot_Value = double;
|
||||
using Plot_Ratio = double;
|
||||
using Plot_Time_Tick = int;
|
||||
using Plot_Duration_Milliseconds = std::uint64_t;
|
||||
using Plot_Duration_Milliseconds = Duration_Milliseconds;
|
||||
using Plot_Partition_Count = std::size_t;
|
||||
using Plot_Index = std::ptrdiff_t;
|
||||
enum class Plot_Partition_Mode : std::uint8_t {
|
||||
|
||||
Reference in New Issue
Block a user