Files
Renderive/Core/primitive/Point_Set.cpp
T
2026-08-02 18:58:35 +08:00

183 lines
7.8 KiB
C++

#include "Point_Set.h"
#include <algorithm>
#include <utility>
#include "../Axis/Abs_Axis_p.h"
#include "../base/Frame_Memory.h"
#include "../base/Memory.h"
#include "../render/Canvas.h"
namespace renderive {
struct Point_Set_Input_Data : Latest_Input_Data {
std::pmr::vector<PointF> points{memory_resource(Memory_Domain::Point_Set)};
std::pmr::vector<Color> colors{memory_resource(Memory_Domain::Point_Set)};
void push(std::span<const PointF> values) {
points.assign(values.begin(), values.end());
colors.clear();
mark_latest_pushed();
}
void push(std::pmr::vector<PointF>&& values) {
points = std::move(values);
colors.clear();
mark_latest_pushed();
}
void push(std::span<const PointF> values, std::span<const Color> color_values) {
points.assign(values.begin(), values.end());
colors.assign(color_values.begin(), color_values.end());
mark_latest_pushed();
}
void push(std::pmr::vector<PointF>&& values, std::pmr::vector<Color>&& color_values) {
points = std::move(values);
colors = std::move(color_values);
mark_latest_pushed();
}
template <typename Handler>
void read_all(Handler handler) {
if (pending)
handler(points, colors);
}
void clear() override {
points.clear();
colors.clear();
clear_latest();
}
};
struct Point_Set_Render_State : Render_State, Point_Set_Prop {};
struct Point_Set_Private : Typed_Render_Data<Point_Set, Point_Set_Render_State, Point_Set_Input_Data> {
std::pmr::vector<PointF> data_points{memory_resource(Memory_Domain::Point_Set)};
std::pmr::vector<Color> data_colors{memory_resource(Memory_Domain::Point_Set)};
void prepare_data(const Render_Frame_Snapshot&, const Renderable_Frame_View& frame_view) override {
Point_Set_Input_Data* input = render_input_data(frame_view);
if (!input)
return;
input->read_all([this](std::pmr::vector<PointF>& points, std::pmr::vector<Color>& colors) {
data_points.swap(points);
data_colors.swap(colors);
});
frame_view.consume_input();
}
void draw_point(Canvas& canvas, const PointF& point, const Point_Set_Render_State* s) {
double half = s->size / 2.0;
if (s->shape == Point_Set_Shape::Circle) {
canvas.draw_ellipse(point, half, half);
}
else if (s->shape == Point_Set_Shape::Square) {
canvas.draw_rect(RectF{point.x - half, point.y - half, s->size, s->size});
}
else {
canvas.draw_line(PointF{point.x - half, point.y}, PointF{point.x + half, point.y});
canvas.draw_line(PointF{point.x, point.y - half}, PointF{point.x, point.y + half});
}
}
void draw(Canvas& canvas, const Render_Frame_Snapshot& snapshot, const Renderable_Frame_View& frame_view) override {
Point_Set_Render_State* s = render_state(frame_view);
if (!s)
return;
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(), snapshot);
std::pmr::vector<PointF> points(frame_memory_resource());
points.reserve(data_points.size());
for (int i = 0; i < data_points.size(); ++i) {
const PointF& point = data_points.at(i);
points.push_back(mapping.map(point));
}
canvas.save();
canvas.set_antialias(s->antialias);
canvas.set_pen(s->pen);
canvas.set_brush(s->brush);
if (data_colors.size() == points.size()) {
for (int i = 0; i < points.size(); ++i) {
Pen pen = s->pen;
Brush brush = s->brush;
pen.color = data_colors.at(i);
brush.color = data_colors.at(i);
canvas.set_pen(pen);
canvas.set_brush(brush);
if (s->shape == Point_Set_Shape::Pixel)
canvas.draw_point(points.at(i));
else
draw_point(canvas, points.at(i), s);
}
}
else if (s->shape == Point_Set_Shape::Pixel) {
canvas.draw_points(std::span<const PointF>(points.data(), points.size()));
}
else {
for (const PointF& point : points) {
draw_point(canvas, point, s);
}
}
canvas.restore();
}
};
RENDERIVE_DEFINE_RENDERABLE_BINDING(Point_Set, Point_Set_Private, Point_Set_Render_State, Point_Set_Input_Data, "point_set")
void Point_Set::update_points(std::span<const PointF> points) {
if (!ok())
return;
Render_Input_Lease<Point_Set_Private, Point_Set_Input_Data> input(d());
input->push(points);
}
void Point_Set::update_points(std::pmr::vector<PointF>&& points) {
if (!ok())
return;
Render_Input_Lease<Point_Set_Private, Point_Set_Input_Data> input(d());
input->push(std::move(points));
}
void Point_Set::update_colored_points(std::span<const PointF> points, std::span<const Color> colors) {
if (points.size() != colors.size())
return;
if (!ok())
return;
Render_Input_Lease<Point_Set_Private, Point_Set_Input_Data> input(d());
input->push(points, colors);
}
void Point_Set::update_colored_points(std::pmr::vector<PointF>&& points, std::pmr::vector<Color>&& colors) {
if (points.size() != colors.size())
return;
if (!ok())
return;
Render_Input_Lease<Point_Set_Private, Point_Set_Input_Data> input(d());
input->push(std::move(points), std::move(colors));
}
RENDERIVE_DEFINE_WEAK_STATE_PROP(Point_Set, Point_Set_Render_State, Abs_Axis, domain_axis)
RENDERIVE_DEFINE_WEAK_STATE_PROP(Point_Set, Point_Set_Render_State, Abs_Axis, value_axis)
double Point_Set::size() {
return d()->edit_state_value(&Point_Set_Render_State::size);
}
void Point_Set::set_size(double value) {
d()->set_state_value(&Point_Set_Render_State::size, std::max(1.0, value));
}
RENDERIVE_DEFINE_STATE_PROP(Point_Set, Point_Set_Render_State, Pen, pen)
RENDERIVE_DEFINE_STATE_PROP(Point_Set, Point_Set_Render_State, Brush, brush)
RENDERIVE_DEFINE_STATE_PROP(Point_Set, Point_Set_Render_State, bool, antialias)
RENDERIVE_DEFINE_STATE_PROP(Point_Set, Point_Set_Render_State, Point_Set_Shape, shape)
Point_Set::Builder::Builder(std::shared_ptr<Renderable> parent, std::shared_ptr<Abs_Axis> domain_axis, std::shared_ptr<Abs_Axis> value_axis) {
ASSERT(parent, "Point_Set build error! parent == nullptr");
ASSERT(domain_axis && value_axis, "Point_Set build error! axis == nullptr");
ASSERT(domain_axis->attached_to_plot(), "Point_Set build error! domain_axis->plot == nullptr");
ASSERT(domain_axis->shares_plot_with(*value_axis), "Point_Set build error! domain_axis->plot != value_axis->plot");
ASSERT(parent->shares_plot_with(*domain_axis), "Point_Set build error! parent->plot != axis->plot");
ASSERT(domain_axis->orientation() != value_axis->orientation(), "Point_Set build error! axes must be orthogonal");
this->parent = parent;
this->domain_axis = domain_axis;
this->value_axis = value_axis;
}
std::shared_ptr<Point_Set> Point_Set::Builder::build() {
auto ret = renderive::make_shared<Point_Set>();
ret->init(parent);
Point_Set_Private* pd = ret->d();
Render_Edit_Lease<Point_Set_Private, Point_Set_Render_State> edit(pd);
Point_Set_Render_State* sc = edit.operator->();
PROP_R(std::weak_ptr<Abs_Axis>, domain_axis)
PROP_R(std::weak_ptr<Abs_Axis>, value_axis)
PROP_R(double, size)
PROP_R(Pen, pen)
PROP_R(Brush, brush)
PROP_R(bool, antialias)
PROP_R(Point_Set_Shape, shape)
sc->size = std::max(1.0, sc->size);
return ret;
}
} // namespace renderive