117 lines
5.1 KiB
C++
117 lines
5.1 KiB
C++
#include "Fill_Area.h"
|
|
#include <utility>
|
|
#include "../Axis/Abs_Axis_p.h"
|
|
#include "../base/Frame_Memory.h"
|
|
#include "../base/Memory.h"
|
|
#include "../render/Canvas.h"
|
|
namespace renderive {
|
|
struct Fill_Area_Input_Data : Latest_Input_Data {
|
|
std::pmr::vector<PointF> points{memory_resource(Memory_Domain::Curve)};
|
|
void push(std::span<const PointF> values) {
|
|
points.assign(values.begin(), values.end());
|
|
mark_latest_pushed();
|
|
}
|
|
void push(std::pmr::vector<PointF>&& values) {
|
|
points = std::move(values);
|
|
mark_latest_pushed();
|
|
}
|
|
template <typename Handler>
|
|
void read_all(Handler handler) {
|
|
if (pending)
|
|
handler(points);
|
|
}
|
|
void clear() override {
|
|
points.clear();
|
|
clear_latest();
|
|
}
|
|
};
|
|
struct Fill_Area_Render_State : Render_State, Fill_Area_Prop {};
|
|
struct Fill_Area_Private : Typed_Render_Data<Fill_Area, Fill_Area_Render_State, Fill_Area_Input_Data> {
|
|
std::pmr::vector<PointF> data_points{memory_resource(Memory_Domain::Curve)};
|
|
void prepare_data(const Render_Frame_Snapshot&) override {
|
|
sync_state_pipeline();
|
|
Fill_Area_Input_Data* input = render_input_data();
|
|
input->read_all([this](std::pmr::vector<PointF>& points) {
|
|
data_points.swap(points);
|
|
});
|
|
clear_render_input();
|
|
}
|
|
void draw(Canvas& canvas, const Render_Frame_Snapshot&) override {
|
|
Fill_Area_Render_State* s = render_state();
|
|
auto domain_axis = s->domain_axis.lock();
|
|
auto value_axis = s->value_axis.lock();
|
|
if (!domain_axis || !value_axis || data_points.empty())
|
|
return;
|
|
Axis_Mapping_2D mapping = Axis_Render_Access::mapping(domain_axis.get(), value_axis.get());
|
|
std::pmr::vector<PointF> polygon(frame_memory_resource());
|
|
if (s->mode == Fill_Area_Mode::To_Baseline) {
|
|
polygon.resize(data_points.size() + 2);
|
|
polygon.front() = mapping.map(data_points.front().x, s->baseline);
|
|
polygon.back() = mapping.map(data_points.back().x, s->baseline);
|
|
for (int i = 0; i < data_points.size(); ++i) {
|
|
const PointF& point = data_points.at(i);
|
|
polygon[i + 1] = mapping.map(point);
|
|
}
|
|
}
|
|
else {
|
|
polygon.resize(data_points.size());
|
|
for (int i = 0; i < data_points.size(); ++i) {
|
|
const PointF& point = data_points.at(i);
|
|
polygon[i] = mapping.map(point);
|
|
}
|
|
}
|
|
canvas.save();
|
|
canvas.set_antialias(s->antialias);
|
|
canvas.set_pen(s->pen);
|
|
canvas.set_brush(s->brush);
|
|
canvas.draw_polygon(std::span<const PointF>(polygon.data(), polygon.size()), false);
|
|
canvas.restore();
|
|
}
|
|
};
|
|
RENDERIVE_DEFINE_RENDERABLE_BINDING(Fill_Area, Fill_Area_Private, Fill_Area_Render_State, Fill_Area_Input_Data, "FillArea")
|
|
void Fill_Area::update_points(std::span<const PointF> points) {
|
|
if (!ok())
|
|
return;
|
|
Render_Input_Lease<Fill_Area_Private, Fill_Area_Input_Data> input(d());
|
|
input->push(points);
|
|
}
|
|
void Fill_Area::update_points(std::pmr::vector<PointF>&& points) {
|
|
if (!ok())
|
|
return;
|
|
Render_Input_Lease<Fill_Area_Private, Fill_Area_Input_Data> input(d());
|
|
input->push(std::move(points));
|
|
}
|
|
RENDERIVE_DEFINE_WEAK_STATE_PROP(Fill_Area, Fill_Area_Render_State, Abs_Axis, domain_axis)
|
|
RENDERIVE_DEFINE_WEAK_STATE_PROP(Fill_Area, Fill_Area_Render_State, Abs_Axis, value_axis)
|
|
RENDERIVE_DEFINE_STATE_PROP(Fill_Area, Fill_Area_Render_State, double, baseline)
|
|
RENDERIVE_DEFINE_STATE_PROP(Fill_Area, Fill_Area_Render_State, Brush, brush)
|
|
RENDERIVE_DEFINE_STATE_PROP(Fill_Area, Fill_Area_Render_State, Pen, pen)
|
|
RENDERIVE_DEFINE_STATE_PROP(Fill_Area, Fill_Area_Render_State, bool, antialias)
|
|
RENDERIVE_DEFINE_STATE_PROP(Fill_Area, Fill_Area_Render_State, Fill_Area_Mode, mode)
|
|
Fill_Area::Builder::Builder(std::shared_ptr<Renderable> parent, std::shared_ptr<Abs_Axis> domain_axis, std::shared_ptr<Abs_Axis> value_axis) {
|
|
ASSERT(parent, "Fill_Area build error! parent == nullptr");
|
|
ASSERT(domain_axis && value_axis, "Fill_Area build error! axis == nullptr");
|
|
ASSERT(domain_axis->attached_to_plot(), "Fill_Area build error! domain_axis->plot == nullptr");
|
|
ASSERT(domain_axis->shares_plot_with(*value_axis), "Fill_Area build error! domain_axis->plot != value_axis->plot");
|
|
ASSERT(parent->shares_plot_with(*domain_axis), "Fill_Area build error! parent->plot != axis->plot");
|
|
ASSERT(domain_axis->orientation() != value_axis->orientation(), "Fill_Area build error! axes must be orthogonal");
|
|
this->parent = parent;
|
|
this->domain_axis = domain_axis;
|
|
this->value_axis = value_axis;
|
|
}
|
|
std::shared_ptr<Fill_Area> Fill_Area::Builder::build() {
|
|
auto ret = renderive::make_shared<Fill_Area>();
|
|
ret->init(parent);
|
|
Fill_Area_Private* pd = ret->d();
|
|
Fill_Area_Render_State* sc = reinterpret_cast<Fill_Area_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(double, baseline)
|
|
PROP_R(Brush, brush)
|
|
PROP_R(Pen, pen)
|
|
PROP_R(bool, antialias)
|
|
PROP_R(Fill_Area_Mode, mode)
|
|
return ret;
|
|
}
|
|
} // namespace renderive
|