Warning, file /include/boost/math/interpolators/detail/bezier_polynomial_detail.hpp was not indexed
or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001
0002
0003
0004
0005
0006
0007 #ifndef BOOST_MATH_INTERPOLATORS_BEZIER_POLYNOMIAL_DETAIL_HPP
0008 #define BOOST_MATH_INTERPOLATORS_BEZIER_POLYNOMIAL_DETAIL_HPP
0009
0010 #include <stdexcept>
0011 #include <iostream>
0012 #include <string>
0013 #include <limits>
0014
0015 namespace boost::math::interpolators::detail {
0016
0017
0018 template <class RandomAccessContainer>
0019 static inline RandomAccessContainer& get_bezier_storage()
0020 {
0021 static thread_local RandomAccessContainer the_storage;
0022 return the_storage;
0023 }
0024
0025
0026 template <class RandomAccessContainer>
0027 class bezier_polynomial_imp
0028 {
0029 public:
0030 using Point = typename RandomAccessContainer::value_type;
0031 using Real = typename Point::value_type;
0032 using Z = typename RandomAccessContainer::size_type;
0033
0034 bezier_polynomial_imp(RandomAccessContainer && control_points)
0035 {
0036 using std::to_string;
0037 if (control_points.size() < 2) {
0038 std::string err = std::string(__FILE__) + ":" + to_string(__LINE__)
0039 + " At least two points are required to form a Bezier curve. Only " + to_string(control_points.size()) + " points have been provided.";
0040 throw std::logic_error(err);
0041 }
0042 Z dimension = control_points[0].size();
0043 for (Z i = 0; i < control_points.size(); ++i) {
0044 if (control_points[i].size() != dimension) {
0045 std::string err = std::string(__FILE__) + ":" + to_string(__LINE__)
0046 + " All points passed to the Bezier polynomial must have the same dimension.";
0047 throw std::logic_error(err);
0048 }
0049 }
0050 control_points_ = std::move(control_points);
0051 auto & storage = get_bezier_storage<RandomAccessContainer>();
0052 if (storage.size() < control_points_.size() -1) {
0053 storage.resize(control_points_.size() -1);
0054 }
0055 }
0056
0057 inline Point operator()(Real t) const
0058 {
0059 if (t < 0 || t > 1) {
0060 std::cerr << __FILE__ << ":" << __LINE__ << ":" << __func__ << "\n";
0061 std::cerr << "Querying the Bezier curve interpolator at t = " << t << " is not allowed; t in [0,1] is required.\n";
0062 Point p;
0063 for (Z i = 0; i < p.size(); ++i) {
0064 p[i] = std::numeric_limits<Real>::quiet_NaN();
0065 }
0066 return p;
0067 }
0068
0069 auto & scratch_space = get_bezier_storage<RandomAccessContainer>();
0070 for (Z i = 0; i < control_points_.size() - 1; ++i) {
0071 for (Z j = 0; j < control_points_[0].size(); ++j) {
0072 scratch_space[i][j] = (1-t)*control_points_[i][j] + t*control_points_[i+1][j];
0073 }
0074 }
0075
0076 decasteljau_recursion(scratch_space, control_points_.size() - 1, t);
0077 return scratch_space[0];
0078 }
0079
0080 Point prime(Real t) {
0081 auto & scratch_space = get_bezier_storage<RandomAccessContainer>();
0082 for (Z i = 0; i < control_points_.size() - 1; ++i) {
0083 for (Z j = 0; j < control_points_[0].size(); ++j) {
0084 scratch_space[i][j] = control_points_[i+1][j] - control_points_[i][j];
0085 }
0086 }
0087 decasteljau_recursion(scratch_space, control_points_.size() - 1, t);
0088 for (Z j = 0; j < control_points_[0].size(); ++j) {
0089 scratch_space[0][j] *= (control_points_.size()-1);
0090 }
0091 return scratch_space[0];
0092 }
0093
0094
0095 void edit_control_point(Point const & p, Z index)
0096 {
0097 if (index >= control_points_.size()) {
0098 std::cerr << __FILE__ << ":" << __LINE__ << ":" << __func__ << "\n";
0099 std::cerr << "Attempting to edit a control point outside the bounds of the container; requested edit of index " << index << ", but there are only " << control_points_.size() << " control points.\n";
0100 return;
0101 }
0102 control_points_[index] = p;
0103 }
0104
0105 RandomAccessContainer const & control_points() const {
0106 return control_points_;
0107 }
0108
0109
0110
0111
0112
0113
0114
0115
0116
0117
0118
0119
0120
0121
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131 friend std::ostream& operator<<(std::ostream& out, bezier_polynomial_imp<RandomAccessContainer> const & bp) {
0132 out << "{";
0133 for (Z i = 0; i < bp.control_points_.size() - 1; ++i) {
0134 out << "(";
0135 for (Z j = 0; j < bp.control_points_[0].size() - 1; ++j) {
0136 out << bp.control_points_[i][j] << ", ";
0137 }
0138 out << bp.control_points_[i][bp.control_points_[0].size() - 1] << "), ";
0139 }
0140 out << "(";
0141 for (Z j = 0; j < bp.control_points_[0].size() - 1; ++j) {
0142 out << bp.control_points_.back()[j] << ", ";
0143 }
0144 out << bp.control_points_.back()[bp.control_points_[0].size() - 1] << ")}";
0145 return out;
0146 }
0147
0148 private:
0149
0150 void decasteljau_recursion(RandomAccessContainer & points, Z n, Real t) const {
0151 if (n <= 1) {
0152 return;
0153 }
0154 for (Z i = 0; i < n - 1; ++i) {
0155 for (Z j = 0; j < points[0].size(); ++j) {
0156 points[i][j] = (1-t)*points[i][j] + t*points[i+1][j];
0157 }
0158 }
0159 decasteljau_recursion(points, n - 1, t);
0160 }
0161
0162 RandomAccessContainer control_points_;
0163 };
0164
0165
0166 }
0167 #endif