#include "Point_Set.h" #include #include #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 points{memory_resource(Memory_Domain::Point_Set)}; std::pmr::vector colors{memory_resource(Memory_Domain::Point_Set)}; void push(std::span values) { points.assign(values.begin(), values.end()); colors.clear(); mark_latest_pushed(); } void push(std::pmr::vector&& values) { points = std::move(values); colors.clear(); mark_latest_pushed(); } void push(std::span values, std::span color_values) { points.assign(values.begin(), values.end()); colors.assign(color_values.begin(), color_values.end()); mark_latest_pushed(); } void push(std::pmr::vector&& values, std::pmr::vector&& color_values) { points = std::move(values); colors = std::move(color_values); mark_latest_pushed(); } template 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 { std::pmr::vector data_points{memory_resource(Memory_Domain::Point_Set)}; std::pmr::vector 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& points, std::pmr::vector& 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 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(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 points) { if (!ok()) return; Render_Input_Lease input(d()); input->push(points); } void Point_Set::update_points(std::pmr::vector&& points) { if (!ok()) return; Render_Input_Lease input(d()); input->push(std::move(points)); } void Point_Set::update_colored_points(std::span points, std::span colors) { if (points.size() != colors.size()) return; if (!ok()) return; Render_Input_Lease input(d()); input->push(points, colors); } void Point_Set::update_colored_points(std::pmr::vector&& points, std::pmr::vector&& colors) { if (points.size() != colors.size()) return; if (!ok()) return; Render_Input_Lease 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 parent, std::shared_ptr domain_axis, std::shared_ptr 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::Builder::build() { auto ret = renderive::make_shared(); ret->init(parent); Point_Set_Private* pd = ret->d(); Render_Edit_Lease edit(pd); Point_Set_Render_State* sc = edit.operator->(); PROP_R(std::weak_ptr, domain_axis) PROP_R(std::weak_ptr, 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