Files
Renderive/Renderive/primitive/Point_Set.cpp
T
2026-07-31 20:11:39 +08:00

192 lines
8.6 KiB
C++

#include "Point_Set.h"
#include <utility>
#include "../Axis/Abs_Axis_p.h"
#include "../base/Frame_Memory.h"
#include "../base/Memory.h"
#include "../qt/Core_Geometry_Adapter.h"
namespace renderive {
struct Point_Set_Input_Data : Latest_Input_Data {
std::pmr::vector<QPointF> points{memory_resource(Memory_Domain::Point_Set)};
std::pmr::vector<QColor> colors{memory_resource(Memory_Domain::Point_Set)};
void push(std::span<const QPointF> values) {
points.assign(values.begin(), values.end());
colors.clear();
mark_latest_pushed();
}
void push(std::pmr::vector<QPointF>&& values) {
points = std::move(values);
colors.clear();
mark_latest_pushed();
}
void push(std::span<const QPointF> values, std::span<const QColor> color_values) {
points.assign(values.begin(), values.end());
colors.assign(color_values.begin(), color_values.end());
mark_latest_pushed();
}
void push(std::pmr::vector<QPointF>&& values, std::pmr::vector<QColor>&& 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<QPointF> data_points{memory_resource(Memory_Domain::Point_Set)};
std::pmr::vector<QColor> data_colors{memory_resource(Memory_Domain::Point_Set)};
void prepare_data(const Plot_Render_Snapshot&) override {
sync_state_pipeline();
Point_Set_Input_Data* input = render_input_data();
input->read_all([this](std::pmr::vector<QPointF>& points, std::pmr::vector<QColor>& colors) {
data_points.swap(points);
data_colors.swap(colors);
});
clear_render_input();
}
void draw_point(Raster_Canvas* painter, const QPointF& point, const Point_Set_Render_State* s) {
double half = s->size / 2.0;
if (s->shape == Point_Set_Shape::Circle) {
painter->drawEllipse(point, half, half);
}
else if (s->shape == Point_Set_Shape::Square) {
painter->drawRect(QRectF(point.x() - half, point.y() - half, s->size, s->size));
}
else {
painter->drawLine(QPointF(point.x() - half, point.y()), QPointF(point.x() + half, point.y()));
painter->drawLine(QPointF(point.x(), point.y() - half), QPointF(point.x(), point.y() + half));
}
}
void rasterize(Frame_Raster_Context& context, const Plot_Render_Snapshot&) override {
Raster_Canvas* painter = &context.canvas();
Point_Set_Render_State* s = render_state();
auto x_axis = s->x_axis.lock();
auto y_axis = s->y_axis.lock();
if (!x_axis || !y_axis || data_points.empty())
return;
const core::Axis_Pair_Transform axes = qt_bridge::axis_pair(*x_axis, *y_axis);
const std::vector<Point> source_points = qt_bridge::to_core_points(data_points);
const std::vector<Point> mapped_points = core::prepare_point_set_geometry(axes, source_points);
std::pmr::vector<QPointF> points(frame_memory_resource());
points.reserve(mapped_points.size());
for (const Point point : mapped_points)
points.push_back(qt_bridge::to_qt_point(point));
painter->save();
painter->setPen(s->pen);
painter->setBrush(s->brush);
if (data_colors.size() == points.size()) {
for (int i = 0; i < points.size(); ++i) {
QPen pen = s->pen;
QBrush brush = s->brush;
pen.setColor(data_colors.at(i));
brush.setColor(data_colors.at(i));
painter->setPen(pen);
painter->setBrush(brush);
if (s->shape == Point_Set_Shape::Pixel)
painter->drawPoint(points.at(i));
else
draw_point(painter, points.at(i), s);
}
}
else if (s->shape == Point_Set_Shape::Pixel) {
painter->drawPoints(points.data(), points.size());
}
else {
for (const QPointF& point : points) {
draw_point(painter, point, s);
}
}
painter->restore();
}
std::size_t estimated_frame_memory(const Plot_Render_Snapshot&) override {
return data_points.size() * sizeof(QPointF) + 8 * 1024;
}
};
RENDERIVE_DEFINE_RENDERABLE_BINDING(Point_Set, Point_Set_Private, Point_Set_Render_State, Point_Set_Input_Data, "point_set")
void Point_Set::give_points(std::span<const QPointF> points, bool notify_render) {
if (notify_render && !ok())
return;
auto context = plot_context.lock();
if (!notify_render && (get_retiring() || !render_data() || !context || context->destroying.load(std::memory_order_acquire)))
return;
Render_Input_Lease<Point_Set_Private, Point_Set_Input_Data> input(d(), notify_render);
input->push(points);
}
void Point_Set::give_points(std::pmr::vector<QPointF>&& points, bool notify_render) {
if (notify_render && !ok())
return;
auto context = plot_context.lock();
if (!notify_render && (get_retiring() || !render_data() || !context || context->destroying.load(std::memory_order_acquire)))
return;
Render_Input_Lease<Point_Set_Private, Point_Set_Input_Data> input(d(), notify_render);
input->push(std::move(points));
}
void Point_Set::give_colored_points(std::span<const QPointF> points, std::span<const QColor> colors, bool notify_render) {
if (points.size() != colors.size())
return;
if (notify_render && !ok())
return;
auto context = plot_context.lock();
if (!notify_render && (get_retiring() || !render_data() || !context || context->destroying.load(std::memory_order_acquire)))
return;
Render_Input_Lease<Point_Set_Private, Point_Set_Input_Data> input(d(), notify_render);
input->push(points, colors);
}
void Point_Set::give_colored_points(std::pmr::vector<QPointF>&& points, std::pmr::vector<QColor>&& colors, bool notify_render) {
if (points.size() != colors.size())
return;
if (notify_render && !ok())
return;
auto context = plot_context.lock();
if (!notify_render && (get_retiring() || !render_data() || !context || context->destroying.load(std::memory_order_acquire)))
return;
Render_Input_Lease<Point_Set_Private, Point_Set_Input_Data> input(d(), notify_render);
input->push(std::move(points), std::move(colors));
}
RENDERIVE_DEFINE_WEAK_STATE_PROP(Point_Set, Point_Set_Render_State, Abs_Axis, x_axis)
RENDERIVE_DEFINE_WEAK_STATE_PROP(Point_Set, Point_Set_Render_State, Abs_Axis, y_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, qMax(1.0, value));
}
RENDERIVE_DEFINE_STATE_PROP(Point_Set, Point_Set_Render_State, QPen, pen)
RENDERIVE_DEFINE_STATE_PROP(Point_Set, Point_Set_Render_State, QBrush, 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> x_axis, std::shared_ptr<Abs_Axis> y_axis) {
ASSERT(parent, "Point_Set build error! parent == nullptr");
ASSERT(x_axis && y_axis, "Point_Set build error! axis == nullptr");
ASSERT(x_axis->is_attached(), "Point_Set build error! x_axis is detached");
ASSERT(x_axis->shares_plot_with(*y_axis), "Point_Set build error! axes belong to different plots");
ASSERT(parent->shares_plot_with(*x_axis), "Point_Set build error! parent and axes belong to different plots");
this->parent = parent;
this->x_axis = x_axis;
this->y_axis = y_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();
Point_Set_Render_State* sc = reinterpret_cast<Point_Set_Render_State*>(pd->state(Data_Buffer_Role::Edit));
PROP_R(std::weak_ptr<Abs_Axis>, x_axis)
PROP_R(std::weak_ptr<Abs_Axis>, y_axis)
PROP_R(double, size)
PROP_R(QPen, pen)
PROP_R(QBrush, brush)
PROP_R(bool, antialias)
PROP_R(Point_Set_Shape, shape)
sc->size = qMax(1.0, sc->size);
return ret;
}
} // namespace renderive