Refactor geom::bezier: extract a free-function de Casteljau's algorithm & support changing control points

This commit is contained in:
Nikita Lisitsa 2022-05-07 14:00:29 +03:00
parent a368eb32ff
commit a22ea3d02e

View file

@ -8,9 +8,24 @@
namespace psemek::geom
{
// In-place de Casteljau's algorithm
template <typename Iterator, typename T>
auto de_casteljau(Iterator begin, Iterator end, T const & t)
{
while (std::next(begin) != end)
{
for (auto it = begin, jt = std::next(begin); jt != end; it = jt++)
*it = lerp(*it, *jt, t);
--end;
}
return *begin;
}
template <typename Point>
struct bezier
{
bezier() = default;
bezier(std::vector<Point> points)
: points_(std::move(points))
{
@ -19,23 +34,34 @@ namespace psemek::geom
temp_.resize(points_.size());
}
std::vector<Point> & points()
{
return points_;
}
template <typename T>
auto operator()(T const & t) const
{
// In-place de Casteljau's algorithm
temp_ = points_;
return de_casteljau(temp_.begin(), temp_.end(), t);
}
template <typename T>
auto tangent(T const & t) const
{
// In-place de Casteljau's algorithm for derivative
tangent_temp_.resize(points_.size() - 1);
for (std::size_t k = 0; k + 1 < points_.size(); ++k)
{
for (std::size_t i = 0; i + k + 1 < points_.size(); ++i)
temp_[i] = lerp(temp_[i], temp_[i + 1], t);
}
return temp_.front();
tangent_temp_[k] = points_[k + 1] - points_[k];
return static_cast<T>(points_.size()) * de_casteljau(tangent_temp_.begin(), tangent_temp_.end(), t);
}
private:
std::vector<Point> const points_;
using vector_type = decltype(Point{} - Point{});
std::vector<Point> points_;
std::vector<Point> mutable temp_;
std::vector<vector_type> mutable tangent_temp_;
};
}