26#include <fmt/format.h>
27#include <opencv2/imgproc.hpp>
34namespace func_sketch::plotter {
46[[nodiscard]] cv::Point adjust_text_position(
const cv::Point& position,
47 const cv::Size& text_size,
const cv::Size& image_size) {
48 cv::Point adjusted_position = position;
50 adjusted_position.x = std::max(adjusted_position.x, 0);
52 std::min(adjusted_position.x, image_size.width - text_size.width);
54 adjusted_position.y = std::max(adjusted_position.y, 0);
56 std::min(adjusted_position.y, image_size.height - text_size.height);
58 return adjusted_position;
70void update_axis_ticks(
const PlotRange& range,
const cv::MatSize& image_size,
73 const std::size_t approx_num_ticks_x = std::max(
static_cast<std::size_t
>(1),
74 static_cast<std::size_t
>(image_size[1]) /
75 config.num_pixels_per_tick_in_x_axis());
76 const std::size_t approx_num_ticks_y = std::max(
static_cast<std::size_t
>(1),
77 static_cast<std::size_t
>(image_size[0]) /
78 config.num_pixels_per_tick_in_y_axis());
85constexpr int plot_text_font_face = cv::FONT_HERSHEY_SIMPLEX;
88constexpr int plot_text_thickness = 1;
97[[nodiscard]]
int compute_required_width_for_y_axis_tick_labels(
99 const int font_size = config.tick_label_font_size();
100 const double font_scale =
101 cv::getFontScaleFromHeight(plot_text_font_face, font_size);
102 int required_width = 0;
103 for (
const auto& text : y_axis_ticks.strings) {
104 const cv::Size text_size = cv::getTextSize(text, plot_text_font_face,
105 font_scale, plot_text_thickness,
nullptr);
106 required_width = std::max(required_width, text_size.width);
108 return required_width;
128 const auto size = image.size;
131 const int required_width_for_y_axis_tick_labels =
133 const int margin_for_y_axis_tick_labels =
config_.tick_label_font_size();
135 required_width_for_y_axis_tick_labels + margin_for_y_axis_tick_labels);
147 const std::vector<Point>& samples,
const RGBColor& color,
Image& image) {
148 const auto size = image.size;
151 const int line_width =
config_.curve_line_width();
153 const std::size_t num_samples = samples.size();
154 if (num_samples < 2) {
157 for (std::size_t i = 0; i < num_samples - 1; ++i) {
158 Point start_xy = samples[i];
159 Point end_xy = samples[i + 1];
161 const bool is_start_in_range =
range_.contains(start_xy);
162 const bool is_end_in_range =
range_.contains(end_xy);
163 if (!is_start_in_range && !is_end_in_range) {
169 if (std::isnan(start_xy.
x) || std::isnan(start_xy.
y) ||
170 std::isnan(end_xy.
x) || std::isnan(end_xy.
y)) {
175 if (!is_start_in_range) {
182 if (!is_end_in_range) {
195 const auto size = image.size;
199 const int line_width = (x_value == 0.0) ?
config_.zero_line_width()
208 const int line_width = (y_value == 0.0) ?
config_.zero_line_width()
218 const auto size = image.size;
226 Point{.x =
range_.x_range().second, .y = y_value}, color,
229 const int font_size =
config_.tick_label_font_size();
230 const double font_scale =
231 cv::getFontScaleFromHeight(plot_text_font_face, font_size);
234 for (std::size_t i = 0; i <
x_axis_ticks_.values.size(); ++i) {
238 const cv::Size text_size = cv::getTextSize(text, plot_text_font_face,
239 font_scale, plot_text_thickness,
nullptr);
241 const auto base_position =
244 const int tick_margin = font_size / 2;
245 auto top_left_position =
246 cv::Point(base_position.x - text_size.width / 2,
247 base_position.y + tick_margin + text_size.height);
248 top_left_position = adjust_text_position(
249 top_left_position, text_size, cv::Size(size[1], size[0]));
251 cv::putText(image, text, top_left_position, plot_text_font_face,
252 font_scale, color, plot_text_thickness, cv::LINE_AA);
257 const auto size = image.size;
265 Point{.x = x_value, .y =
range_.y_range().second}, color,
268 const int font_size =
config_.tick_label_font_size();
269 const double font_scale =
270 cv::getFontScaleFromHeight(plot_text_font_face, font_size);
273 for (std::size_t i = 0; i <
y_axis_ticks_.values.size(); ++i) {
277 const cv::Size text_size = cv::getTextSize(text, plot_text_font_face,
278 font_scale, plot_text_thickness,
nullptr);
280 const auto base_position =
283 const int tick_margin = font_size / 2;
284 cv::Point top_left_position;
286 cv::Point(base_position.x - tick_margin - text_size.width,
287 base_position.y + text_size.height / 2);
288 top_left_position = adjust_text_position(
289 top_left_position, text_size, cv::Size(size[1], size[0]));
291 cv::putText(image, text, top_left_position, plot_text_font_face,
292 font_scale, color, plot_text_thickness, cv::LINE_AA);
Definition of AxisTicks class.
void generate_axis_ticks(const std::pair< Real, Real > &range, std::size_t approx_num_ticks, AxisTicks &ticks)
Generate ticks of axes.
Class of configurations of a plot.
Class of a range of a plot.
Plotter & config(const PlotConfig &value)
Set the configuration of plots.
void write_curve(const std::vector< Point > &samples, const RGBColor &color, Image &image)
Write a curve on plots.
AxisTicks x_axis_ticks_
Ticks of the x-axis.
void write_y_axis(Image &image)
Write y axis.
void write_x_axis(Image &image)
Write x axis.
PlotConfig config_
Configuration of plots.
PlotRange range_
Range of plots.
Plotter & range(const PlotRange &value)
Set the range of plots.
int left_margin_
Left margin of plots in pixels. (This value is used over the value in config because tuning of the le...
void write_grid_lines(Image &image)
Write grid lines of plots.
Plotter(const PlotRange &range, const PlotConfig &config)
Constructor.
AxisTicks y_axis_ticks_
Ticks of the y-axis.
void write_background(Image &image)
Write background of plots.
Definitions of common types.
double Real
Type of real numbers in this project.
Definition of Plotter class.
Declaration of functions for internal implementation of plotting.
Point compute_intersection_with_range(const Point &point_in_range, const Point &point_out_of_range, const PlotRange &range)
Compute the intersection of a line segment with the boundary of the plot range.
cv::Point convert_position(const Point &position, const PlotRange &range, const PlotConfig &config, int left_margin, const cv::MatSize &size)
Convert a position from plot coordinates to image coordinates.
cv::Scalar convert_color(const RGBColor &color)
Convert a color from RGBColor to cv::Scalar.
void write_line(Image &image, const Point &start_point, const Point &end_point, const cv::Scalar &color, int line_width, const PlotRange &range, const PlotConfig &config, int left_margin)
Write a line on an image.
bool try_clamp_infinity(Point &point, const PlotRange &range)
Try to clamp a point with infinity to the range.
Definition of Point struct.
Struct to represent ticks of axes.