FuncSketch
Loading...
Searching...
No Matches
plotting_util.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2026 MusicScience37 (Kenta Kabashima)
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
21
22#include <cassert>
23#include <cmath>
24
25#include <opencv2/imgproc.hpp>
26
29
30namespace func_sketch::plotter {
31
32cv::Scalar convert_color(const RGBColor& color) {
33 // Use RGB order in this implementation.
34 return cv::Scalar(color.r, color.g, color.b);
35}
36
37cv::Point convert_position(const Point& position, const PlotRange& range,
38 const PlotConfig& config, int left_margin, const cv::MatSize& size) {
39 const int plot_width = size[1] - left_margin - config.right_margin();
40 const int plot_height =
41 size[0] - config.top_margin() - config.bottom_margin();
42 if (plot_width <= 0 || plot_height <= 0) {
43 throw InvalidArgumentException("Too small image size.");
44 }
45
46 const double x_ratio = (position.x - range.x_range().first) /
47 (range.x_range().second - range.x_range().first);
48 const double y_ratio = (position.y - range.y_range().first) /
49 (range.y_range().second - range.y_range().first);
50
51 // This version does not use shift.
52 const int x_in_pixel = static_cast<int>(plot_width * x_ratio) + left_margin;
53 const int y_in_pixel =
54 static_cast<int>(plot_height * (1.0 - y_ratio)) + config.top_margin();
55
56 return cv::Point(x_in_pixel, y_in_pixel);
57}
58
72[[nodiscard]] cv::Point convert_position_with_shift(const Point& position,
73 const PlotRange& range, const PlotConfig& config, int left_margin,
74 const cv::MatSize& size, int shift) {
75 const int plot_width = size[1] - left_margin - config.right_margin();
76 const int plot_height =
77 size[0] - config.top_margin() - config.bottom_margin();
78 if (plot_width <= 0 || plot_height <= 0) {
79 throw InvalidArgumentException("Too small image size.");
80 }
81
82 const double x_ratio = (position.x - range.x_range().first) /
83 (range.x_range().second - range.x_range().first);
84 const double y_ratio = (position.y - range.y_range().first) /
85 (range.y_range().second - range.y_range().first);
86
87 const double x_in_pixel_precise =
88 static_cast<double>(plot_width) * x_ratio +
89 static_cast<double>(left_margin);
90 const double y_in_pixel_precise =
91 static_cast<double>(plot_height) * (1.0 - y_ratio) +
92 static_cast<double>(config.top_margin());
93
94 const double coeff = std::ldexp(1.0, shift);
95 const int x_in_pixel_shifted = static_cast<int>(x_in_pixel_precise * coeff);
96 const int y_in_pixel_shifted = static_cast<int>(y_in_pixel_precise * coeff);
97
98 return cv::Point(x_in_pixel_shifted, y_in_pixel_shifted);
99}
100
101void write_line(Image& image, const Point& start_point, const Point& end_point,
102 const cv::Scalar& color, int line_width, const PlotRange& range,
103 const PlotConfig& config, int left_margin) {
104 // Use shift to draw lines precisely.
105 constexpr int shift = 10;
106 const auto start_pixel = convert_position_with_shift(
107 start_point, range, config, left_margin, image.size, shift);
108 const auto end_pixel = convert_position_with_shift(
109 end_point, range, config, left_margin, image.size, shift);
110 cv::line(
111 image, start_pixel, end_pixel, color, line_width, cv::LINE_AA, shift);
112}
113
114bool try_clamp_infinity(Point& point, const PlotRange& range) {
115 if (std::isinf(point.x) && std::isinf(point.y)) {
116 return false;
117 }
118 if (std::isinf(point.x)) {
119 point.x =
120 (point.x > 0) ? range.x_range().second : range.x_range().first;
121 }
122 if (std::isinf(point.y)) {
123 point.y =
124 (point.y > 0) ? range.y_range().second : range.y_range().first;
125 }
126 return true;
127}
128
138 const Point& point1, const Point& point2, Real x_value) {
139 assert(point1.x != point2.x);
140 const Real slope = (point2.y - point1.y) / (point2.x - point1.x);
141 const Real y_value = point1.y + slope * (x_value - point1.x);
142 return Point{.x = x_value, .y = y_value};
143}
144
154 const Point& point1, const Point& point2, Real y_value) {
155 assert(point1.y != point2.y);
156 const Real slope = (point2.x - point1.x) / (point2.y - point1.y);
157 const Real x_value = point1.x + slope * (y_value - point1.y);
158 return Point{.x = x_value, .y = y_value};
159}
160
162 const Point& point_out_of_range, const PlotRange& range) {
163 Point intersection = point_out_of_range;
164
165 if (intersection.x < range.x_range().first) {
167 point_in_range, intersection, range.x_range().first);
168 } else if (intersection.x > range.x_range().second) {
170 point_in_range, intersection, range.x_range().second);
171 }
172
173 if (intersection.y < range.y_range().first) {
175 point_in_range, intersection, range.y_range().first);
176 } else if (intersection.y > range.y_range().second) {
178 point_in_range, intersection, range.y_range().second);
179 }
180
181 return intersection;
182}
183
184} // namespace func_sketch::plotter
Class of exceptions for invalid arguments.
Definition exceptions.h:37
Class of configurations of a plot.
Definition plot_config.h:97
PlotConfig & top_margin(int value)
Set the top margin of plots in pixels.
PlotConfig & right_margin(int value)
Set the right margin of plots in pixels.
PlotConfig & bottom_margin(int value)
Set the bottom margin of plots in pixels.
Class of a range of a plot.
Definition plot_range.h:35
auto y_range() const noexcept -> std::pair< double, double >
Get Y range.
Definition plot_range.h:74
auto x_range() const noexcept -> std::pair< double, double >
Get X range.
Definition plot_range.h:65
Definitions of common types.
double Real
Type of real numbers in this project.
Definition of exception classes.
cv::Mat Image
Image type.
Definition image.h:29
Point compute_intersection_with_vertical_line(const Point &point1, const Point &point2, Real x_value)
Compute the intersection of a line segment with a vertical line.
Point compute_intersection_with_horizontal_line(const Point &point1, const Point &point2, Real y_value)
Compute the intersection of a line segment with a horizontal line.
cv::Point convert_position_with_shift(const Point &position, const PlotRange &range, const PlotConfig &config, int left_margin, const cv::MatSize &size, int shift)
Convert a position from plot coordinates to image coordinates with shift.
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.
Struct of a point.
Definition point.h:29
double y
Y coordinate.
Definition point.h:34
double x
X coordinate.
Definition point.h:31
Struct of RGB color.
Definition rgb_color.h:31
std::uint8_t g
Green component.
Definition rgb_color.h:36
std::uint8_t r
Red component.
Definition rgb_color.h:33
std::uint8_t b
Blue component.
Definition rgb_color.h:39