26namespace func_sketch::plotter {
51 std::vector<Point> samples;
52 const std::size_t num_points =
config_.initial_num_sample_points();
53 samples.reserve(num_points);
54 for (std::size_t i = 0; i < num_points; ++i) {
56 static_cast<Real>(i) /
static_cast<Real>(num_points - 1);
58 x_ratio * (
range_.x_range().second -
range_.x_range().first);
63 samples.push_back(
Point{.x = x_value, .y = y_value});
70 const std::vector<Point>& initial_samples)
const {
71 std::vector<Point> samples;
75 const std::size_t num_reserved_points = initial_samples.size() * 3;
76 samples.reserve(num_reserved_points);
78 auto initial_sample_iter = initial_samples.begin();
79 std::size_t left_index = 0;
82 while (initial_sample_iter != initial_samples.end() &&
83 samples.size() < left_index + 3) {
84 samples.push_back(*initial_sample_iter);
85 ++initial_sample_iter;
87 const std::size_t num_points_from_here = samples.size() - left_index;
88 if (num_points_from_here < 2) {
94 bool is_divided =
false;
96 function, samples, left_index)) {
99 if (num_points_from_here >= 3) {
101 function, samples, left_index)) {
106 function, samples, left_index)) {
113 if (samples.size() >=
config_.max_num_sample_points()) {
117 samples.end(), initial_sample_iter, initial_samples.end());
126 std::size_t left_index)
const {
127 const auto& left_point = samples[left_index];
128 const auto& right_point = samples[left_index + 1];
129 const double y_diff = std::abs(right_point.y - left_point.y);
130 const double y_range =
range_.y_range().second -
range_.y_range().first;
131 const double y_diff_rate = y_diff / y_range;
132 if (std::isfinite(y_diff_rate) &&
133 y_diff_rate >
config_.max_coordinate_change_rate()) {
141 std::size_t left_index)
const {
142 const auto& left_point = samples[left_index];
143 const auto& mid_point = samples[left_index + 1];
144 const auto& right_point = samples[left_index + 2];
145 const double slope_normalization_coeff =
148 const double left_slope = slope_normalization_coeff *
149 (mid_point.y - left_point.y) / (mid_point.x - left_point.x);
150 const double right_slope = slope_normalization_coeff *
151 (right_point.y - mid_point.y) / (right_point.x - mid_point.x);
152 const double slope_diff = std::abs(right_slope - left_slope);
153 if (std::isfinite(slope_diff) &&
154 slope_diff >
config_.slope_change_threshold()) {
157 const bool is_right_divided =
159 const bool is_left_divided =
161 return is_left_divided || is_right_divided;
168 std::size_t left_index)
const {
169 const auto& left_point = samples[left_index];
170 const auto& right_point = samples[left_index + 1];
171 const bool is_left_finite = std::isfinite(left_point.y);
172 const bool is_right_finite = std::isfinite(right_point.y);
173 if ((is_left_finite && is_right_finite) ||
174 (!is_left_finite && !is_right_finite)) {
181 std::vector<Point>& samples, std::size_t left_index)
const {
182 const std::size_t right_index = left_index + 1;
183 const Point& left_point = samples[left_index];
184 const Point& right_point = samples[right_index];
188 const Point mid_point =
191 samples.begin() +
static_cast<std::ptrdiff_t
>(right_index), mid_point);
197 const Point& right_point)
const {
199 mid_point.
x = 0.5 * (left_point.
x + right_point.
x);
205 const Point& left_point,
const Point& right_point)
const {
206 if (!
range_.contains(left_point) && !
range_.contains(right_point)) {
212 const double x_diff = std::abs(right_point.
x - left_point.
x);
213 const double x_range =
range_.x_range().second -
range_.x_range().first;
214 const double x_diff_rate = x_diff / x_range;
215 if (x_diff_rate <
config_.min_param_change_rate()) {
bool divide_segment_according_to_y_change(const expressions::Expression &function, std::vector< Point > &samples, std::size_t left_index) const
Divide if the change of y is large.
bool divide_segment(const expressions::Expression &function, std::vector< Point > &samples, std::size_t left_index) const
Divide a segment into two segments in sample points if applicable.
std::vector< Point > sample_adaptive_points(const expressions::Expression &function, const std::vector< Point > &initial_samples) const
Sample additional points adaptively.
FunctionSampler & config(const PlotConfig &value)
Set the configuration of plots.
bool divide_segment_when_one_end_is_not_finite(const expressions::Expression &function, std::vector< Point > &samples, std::size_t left_index) const
Divide if one end of the segment is not finite.
std::vector< Point > operator()(const expressions::Expression &function) const
Sample a function for plotting.
FunctionSampler(const PlotRange &range, const PlotConfig &config)
Constructor.
bool divide_segment_according_to_slope_change(const expressions::Expression &function, std::vector< Point > &samples, std::size_t left_index) const
Divide if the change of slope of y is large.
PlotRange range_
Range of plots.
expressions::ExpressionEvaluator evaluator_
Evaluator of expressions.
std::vector< Point > sample_initial_points(const expressions::Expression &function) const
Sample initial points.
PlotConfig config_
Configuration of plots.
bool is_sampling_should_be_skipped(const Point &left_point, const Point &right_point) const
Check the condition to skip sampling of a point between two points.
Point sample_additional_point(const expressions::Expression &function, const Point &left_point, const Point &right_point) const
Sample an additional point between two points.
FunctionSampler & range(const PlotRange &value)
Set the range of plots.
Class of configurations of a plot.
Class of a range of a plot.
double Real
Type of real numbers in this project.
Definition of FunctionSampler class.