diff --git a/libs/geom/include/psemek/geom/bezier.hpp b/libs/geom/include/psemek/geom/bezier.hpp index 8b1610e7..57f9a5f3 100644 --- a/libs/geom/include/psemek/geom/bezier.hpp +++ b/libs/geom/include/psemek/geom/bezier.hpp @@ -8,9 +8,24 @@ namespace psemek::geom { + // In-place de Casteljau's algorithm + template + 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 struct bezier { + bezier() = default; + bezier(std::vector points) : points_(std::move(points)) { @@ -19,23 +34,34 @@ namespace psemek::geom temp_.resize(points_.size()); } + std::vector & points() + { + return points_; + } + template auto operator()(T const & t) const { - // In-place de Casteljau's algorithm temp_ = points_; + return de_casteljau(temp_.begin(), temp_.end(), t); + } + template + 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(points_.size()) * de_casteljau(tangent_temp_.begin(), tangent_temp_.end(), t); } private: - std::vector const points_; + using vector_type = decltype(Point{} - Point{}); + + std::vector points_; std::vector mutable temp_; + std::vector mutable tangent_temp_; }; }