策略抽离

This commit is contained in:
2026-08-02 14:20:27 +08:00
parent 6d000f43b4
commit 2df8959ed6
87 changed files with 2454 additions and 1390 deletions
+64 -38
View File
@@ -9,6 +9,7 @@
#include <optional>
#include <rigtorp/MPMCQueue.h>
#include <system_error>
#include <variant>
#include "../base/Memory.h"
#include "../render/Canvas.h"
namespace renderive {
@@ -19,36 +20,62 @@ enum class Curve_Input_Mode : std::uint8_t {
};
struct Curve_Input_Data : Input_Data {};
struct Curve_Render_State : Render_State, Curve_Prop {};
struct Curve_Sample_Source {
Curve_Sample_Source() : values(memory_resource(Memory_Domain::Curve)) {}
explicit Curve_Sample_Source(std::span<const double> input) : values(memory_resource(Memory_Domain::Curve)) {
values.assign(input.begin(), input.end());
}
explicit Curve_Sample_Source(std::pmr::vector<double>&& input) : values(std::move(input)) {}
std::pmr::vector<double> values;
};
struct Curve_Point_Source {
Curve_Point_Source() : values(memory_resource(Memory_Domain::Curve)) {}
explicit Curve_Point_Source(std::span<const PointF> input) : values(memory_resource(Memory_Domain::Curve)) {
values.assign(input.begin(), input.end());
}
explicit Curve_Point_Source(std::pmr::vector<PointF>&& input) : values(std::move(input)) {}
std::pmr::vector<PointF> values;
};
using Curve_Source = std::variant<std::monostate, Curve_Sample_Source, Curve_Point_Source>;
static Curve_Input_Mode curve_source_mode(const Curve_Source& source) {
if (std::holds_alternative<Curve_Sample_Source>(source))
return Curve_Input_Mode::Samples;
if (std::holds_alternative<Curve_Point_Source>(source))
return Curve_Input_Mode::Points;
return Curve_Input_Mode::None;
}
static std::size_t curve_sample_count(const Curve_Source& source) {
const auto* samples = std::get_if<Curve_Sample_Source>(&source);
return samples ? samples->values.size() : 0u;
}
static std::size_t curve_point_count(const Curve_Source& source) {
const auto* points = std::get_if<Curve_Point_Source>(&source);
return points ? points->values.size() : 0u;
}
struct Curve_Input_Block {
Curve_Input_Mode mode = Curve_Input_Mode::None;
std::pmr::vector<double> samples{memory_resource(Memory_Domain::Curve)};
std::pmr::vector<PointF> points{memory_resource(Memory_Domain::Curve)};
std::shared_ptr<const Curve_Source> source = std::make_shared<Curve_Source>();
std::shared_ptr<Update_State> completion_state;
static std::shared_ptr<Curve_Input_Block> samples_block(std::span<const double> values, std::shared_ptr<Update_State> state = {}) {
auto block = std::make_shared<Curve_Input_Block>();
block->mode = Curve_Input_Mode::Samples;
block->samples.assign(values.begin(), values.end());
block->source = std::make_shared<Curve_Source>(Curve_Sample_Source(values));
block->completion_state = std::move(state);
return block;
}
static std::shared_ptr<Curve_Input_Block> samples_block(std::pmr::vector<double>&& values, std::shared_ptr<Update_State> state = {}) {
auto block = std::make_shared<Curve_Input_Block>();
block->mode = Curve_Input_Mode::Samples;
block->samples = std::move(values);
block->source = std::make_shared<Curve_Source>(Curve_Sample_Source(std::move(values)));
block->completion_state = std::move(state);
return block;
}
static std::shared_ptr<Curve_Input_Block> points_block(std::span<const PointF> values, std::shared_ptr<Update_State> state = {}) {
auto block = std::make_shared<Curve_Input_Block>();
block->mode = Curve_Input_Mode::Points;
block->points.assign(values.begin(), values.end());
block->source = std::make_shared<Curve_Source>(Curve_Point_Source(values));
block->completion_state = std::move(state);
return block;
}
static std::shared_ptr<Curve_Input_Block> points_block(std::pmr::vector<PointF>&& values, std::shared_ptr<Update_State> state = {}) {
auto block = std::make_shared<Curve_Input_Block>();
block->mode = Curve_Input_Mode::Points;
block->points = std::move(values);
block->source = std::make_shared<Curve_Source>(Curve_Point_Source(std::move(values)));
block->completion_state = std::move(state);
return block;
}
@@ -94,15 +121,14 @@ struct Curve_Geometry_Result {
std::pmr::vector<std::shared_ptr<Update_State>> update_states;
};
struct Curve_Geometry_Request {
Curve_Geometry_Request() : samples(memory_resource(Memory_Domain::Curve)), data_points(memory_resource(Memory_Domain::Curve)), update_states(memory_resource(Memory_Domain::Update_Completion)) {}
Curve_Geometry_Request() : update_states(memory_resource(Memory_Domain::Update_Completion)) {}
Curve_Input_Mode mode = Curve_Input_Mode::None;
Axis_Mapping_2D mapping;
Range data_range{0.0, 1.0};
bool visible_range_only{};
Line_Interpolation_Mode interpolation_mode = Line_Interpolation_Mode::Linear_Value;
Line_Sampling_Strategy sample_mode = Line_Sampling_Strategy::Pixel_Min_Max_Envelope;
std::pmr::vector<double> samples;
std::pmr::vector<PointF> data_points;
std::shared_ptr<const Curve_Source> source;
std::pmr::vector<std::shared_ptr<Update_State>> update_states;
};
static Curve_Axis_Geometry_Key curve_axis_key(const Axis_Frame_Snapshot& axis) {
@@ -124,29 +150,30 @@ static void complete_curve_result_states(Curve_Geometry_Result& result, std::err
}
static void build_curve_geometry(Curve_Geometry_Result& result, const Curve_Geometry_Request& request) {
std::pmr::vector<PointF>& points = result.points;
if (request.mode == Curve_Input_Mode::Points) {
points.reserve(request.data_points.size());
for (std::size_t i = 0; i < request.data_points.size(); ++i)
points.push_back(request.mapping.map(request.data_points[i]));
if (!request.source)
return;
if (const auto* data_points = std::get_if<Curve_Point_Source>(request.source.get())) {
points.reserve(data_points->values.size());
for (std::size_t i = 0; i < data_points->values.size(); ++i)
points.push_back(request.mapping.map(data_points->values[i]));
return;
}
if (request.mode != Curve_Input_Mode::Samples || request.samples.size() < 2 || request.data_range.length() == 0.0)
const auto* samples = std::get_if<Curve_Sample_Source>(request.source.get());
if (!samples || samples->values.size() < 2 || request.data_range.length() == 0.0)
return;
if (request.sample_mode == Line_Sampling_Strategy::Pixel_Min_Max_Envelope) {
points = Curve_Utils::build_pixel_envelope_points(request.mapping, request.data_range, static_cast<int>(request.samples.size()), static_cast<int>(request.samples.size()), request.visible_range_only, [&request](int i) {
return request.samples[static_cast<std::size_t>(i)];
points = Curve_Utils::build_pixel_envelope_points(request.mapping, request.data_range, static_cast<int>(samples->values.size()), static_cast<int>(samples->values.size()), request.visible_range_only, [samples](int i) {
return samples->values[static_cast<std::size_t>(i)];
}, memory_resource(Memory_Domain::Curve));
return;
}
points = Curve_Utils::build_resampled_points(request.mapping, request.data_range, static_cast<int>(request.samples.size()), static_cast<int>(request.samples.size()), request.visible_range_only, request.interpolation_mode, [&request](int i) {
return request.samples[static_cast<std::size_t>(i)];
points = Curve_Utils::build_resampled_points(request.mapping, request.data_range, static_cast<int>(samples->values.size()), static_cast<int>(samples->values.size()), request.visible_range_only, request.interpolation_mode, [samples](int i) {
return samples->values[static_cast<std::size_t>(i)];
}, memory_resource(Memory_Domain::Curve));
}
struct Curve_Private : Typed_Render_Data<Curve, Curve_Render_State, Curve_Input_Data> {
static constexpr std::size_t Input_Queue_Capacity = 8;
std::pmr::vector<double> samples{memory_resource(Memory_Domain::Curve)};
std::pmr::vector<PointF> data_points{memory_resource(Memory_Domain::Curve)};
Curve_Input_Mode mode = Curve_Input_Mode::None;
std::shared_ptr<const Curve_Source> source = std::make_shared<Curve_Source>();
rigtorp::MPMCQueue<std::shared_ptr<Curve_Input_Block>> input_queue;
std::atomic_uint64_t dropped_input_count{0};
std::pmr::vector<std::shared_ptr<Update_State>> pending_geometry_update_states{memory_resource(Memory_Domain::Update_Completion)};
@@ -195,16 +222,14 @@ struct Curve_Private : Typed_Render_Data<Curve, Curve_Render_State, Curve_Input_
}
if (!selected)
return;
mode = selected->mode;
samples = std::move(selected->samples);
data_points = std::move(selected->points);
source = std::move(selected->source);
++input_generation;
if (selected->completion_state) {
selected->completion_state->complete_until(Update_Stage::Committed);
pending_geometry_update_states.push_back(std::move(selected->completion_state));
}
}
void prepare_data(const Plot_Render_Snapshot& snapshot) override {
void prepare_data(const Render_Frame_Snapshot& snapshot) override {
(void)snapshot;
sync_state_pipeline();
consume_input_queue();
@@ -226,27 +251,26 @@ struct Curve_Private : Typed_Render_Data<Curve, Curve_Render_State, Curve_Input_
Curve_Geometry_Key key;
key.input_generation = input_generation;
key.state_version = s->version;
key.mode = mode;
key.mode = source ? curve_source_mode(*source) : Curve_Input_Mode::None;
key.sample_mode = s->sample_mode;
key.interpolation_mode = s->interpolation_mode;
key.visible_range_only = s->visible_range_only;
key.data_range = s->data_range;
key.sample_count = samples.size();
key.point_count = data_points.size();
key.sample_count = source ? curve_sample_count(*source) : 0u;
key.point_count = source ? curve_point_count(*source) : 0u;
key.domain = curve_axis_key(mapping.domain);
key.value = curve_axis_key(mapping.value);
if (submitted_geometry_key && key == *submitted_geometry_key)
return;
submitted_geometry_key = key;
auto request = std::make_shared<Curve_Geometry_Request>();
request->mode = mode;
request->mode = key.mode;
request->mapping = mapping;
request->data_range = s->data_range;
request->visible_range_only = s->visible_range_only;
request->interpolation_mode = s->interpolation_mode;
request->sample_mode = s->sample_mode;
request->samples = samples;
request->data_points = data_points;
request->source = source;
request->update_states = std::move(pending_geometry_update_states);
pending_geometry_update_states = std::pmr::vector<std::shared_ptr<Update_State>>(memory_resource(Memory_Domain::Update_Completion));
geometry_result.emplace();
@@ -254,7 +278,7 @@ struct Curve_Private : Typed_Render_Data<Curve, Curve_Render_State, Curve_Input_
build_curve_geometry(*geometry_result, *request);
geometry_result->update_states = std::move(request->update_states);
}
void draw(Canvas& canvas, const Plot_Render_Snapshot& snapshot) override {
void draw(Canvas& canvas, const Render_Frame_Snapshot& snapshot) override {
Curve_Render_State* s = render_state();
if (!geometry_result)
return;
@@ -361,7 +385,7 @@ std::shared_ptr<Curve> Curve::Builder::build() {
auto ret = renderive::make_shared<Curve>();
ret->init(parent);
Curve_Private* pd = ret->d();
Curve_Render_State* sc = reinterpret_cast<Curve_Render_State*>(pd->state(State_Edit));
Curve_Render_State* sc = reinterpret_cast<Curve_Render_State*>(pd->edit_state());
PROP_R(std::weak_ptr<Abs_Axis>, domain_axis)
PROP_R(std::weak_ptr<Abs_Axis>, value_axis)
PROP_R(Range, data_range)
@@ -397,6 +421,8 @@ void Curve_Utils::draw_fill_to_value(Canvas* canvas, std::span<const PointF> poi
void Curve_Utils::append_envelope_point(std::pmr::vector<PointF>& points, const Axis_Mapping_2D& mapping, const Range& data_range, int total_count, int index, double value) {
if (index < 0)
return;
if (!std::isfinite(value))
return;
PointF point = mapping.map(source_index_to_coordinate(data_range, total_count, index), value);
if (!points.empty() && points.back().x == point.x && points.back().y == point.y)
return;