[/
  Copyright 2021 Nick Thompson, John Maddock

  Distributed under the Boost Software License, Version 1.0.
  (See accompanying file LICENSE_1_0.txt or copy at
  http://www.boost.org/LICENSE_1_0.txt).
]

[section:bezier_polynomial Bezier Polynomials]

[heading Synopsis]

``
#include <boost/math/interpolators/bezier_polynomials.hpp>

namespace boost::math::interpolators {

    template<RandomAccessContainer>
    class bezier_polynomial
    {
    public:
        using Point = typename RandomAccessContainer::value_type;
        using Real = typename Point::value_type;
        using Z = typename RandomAccessContainer::size_type;

        bezier_polynomial(RandomAccessContainer&& control_points);

        inline Point operator()(Real t) const;

        inline Point prime(Real t) const;

        void edit_control_point(Point cont & p, Z index);

        RandomAccessContainer const & control_points() const;

        friend std::ostream& operator<<(std::ostream& out, bezier_polynomial<RandomAccessContainer> const & bp);
    };

}
``

[heading Description]

B[eacute]zier polynomials are curves smooth curves which approximate a set of control points.
They are commonly used in computer-aided geometric design.
A basic usage is demonstrated below:

    std::vector<std::array<double, 3>> control_points(4);
    control_points[0] = {0,0,0};
    control_points[1] = {1,0,0};
    control_points[2] = {0,1,0};
    control_points[3] = {0,0,1};
    auto bp = bezier_polynomial(std::move(control_points));
    // Interpolate at t = 0.1:
    std::array<double, 3> point = bp(0.1);

The support of the interpolant is [0,1], and an error message will be written if attempting to evaluate the polynomial outside of these bounds.
At least two points must be passed; creating a polynomial of degree 1.

Control points may be modified via `edit_control_point`, for example:

    std::array<double, 3> endpoint{0,1,1};
    bp.edit_control_point(endpoint, 3);

This replaces the last control point with `endpoint`.

Tangents are computed with the `.prime` member function, and the control points may be referenced with the `.control_points` member function.

The overloaded operator /<</ is disappointing: The control points are simply printed.
Rendering the Bezier and its convex hull seems to be the best "print" statement for it, but this is essentially impossible in modern terminals.

[heading Caveats]

Do not confuse the Bezier polynomial with a Bezier spline.
A Bezier spline has a fixed polynomial order and subdivides the curve into low-order polynomial segments.
/This is not a spline!/
Passing /n/ control points to the `bezier_polynomial` class creates a polynomial of degree n-1, whereas a Bezier spline has a fixed order independent of the number of control points.

Requires C++17 and support for threadlocal storage.


[heading Performance]

The following performance numbers were generated for evaluating the Bezier-polynomial.
The evaluation of the interpolant is [bigo](/N/^2), as expected from de Casteljau's algorithm.


    Run on (16 X 2300 MHz CPU s)
    CPU Caches:
    L1 Data 32 KiB (x8)
    L1 Instruction 32 KiB (x8)
    L2 Unified 256 KiB (x8)
    L3 Unified 16384 KiB (x1)
    ---------------------------------------------------------
    Benchmark                              Time           CPU
    ---------------------------------------------------------
    BezierPolynomial<double>/2        9.07 ns         9.06 ns
    BezierPolynomial<double>/3        13.2 ns         13.1 ns
    BezierPolynomial<double>/4        17.5 ns         17.5 ns
    BezierPolynomial<double>/5        21.7 ns         21.7 ns
    BezierPolynomial<double>/6        27.4 ns         27.4 ns
    BezierPolynomial<double>/7        32.4 ns         32.3 ns
    BezierPolynomial<double>/8        40.4 ns         40.4 ns
    BezierPolynomial<double>/9        51.9 ns         51.8 ns
    BezierPolynomial<double>/10       65.9 ns         65.9 ns
    BezierPolynomial<double>/11       79.1 ns         79.1 ns
    BezierPolynomial<double>/12       83.0 ns         82.9 ns
    BezierPolynomial<double>/13        108 ns          108 ns
    BezierPolynomial<double>/14        119 ns          119 ns
    BezierPolynomial<double>/15        140 ns          140 ns
    BezierPolynomial<double>/16        137 ns          137 ns
    BezierPolynomial<double>/17        151 ns          151 ns
    BezierPolynomial<double>/18        171 ns          171 ns
    BezierPolynomial<double>/19        194 ns          193 ns
    BezierPolynomial<double>/20        213 ns          213 ns
    BezierPolynomial<double>/21        220 ns          220 ns
    BezierPolynomial<double>/22        260 ns          260 ns
    BezierPolynomial<double>/23        266 ns          266 ns
    BezierPolynomial<double>/24        293 ns          292 ns
    BezierPolynomial<double>/25        319 ns          319 ns
    BezierPolynomial<double>/26        336 ns          335 ns
    BezierPolynomial<double>/27        370 ns          370 ns
    BezierPolynomial<double>/28        429 ns          429 ns
    BezierPolynomial<double>/29        443 ns          443 ns
    BezierPolynomial<double>/30        421 ns          421 ns
    BezierPolynomial<double>_BigO       0.52 N^2        0.51 N^2  

The Casteljau recurrence is indeed quadratic in the number of control points, and is chosen for numerical stability.
See /Bezier and B-spline Techniques/, section 2.3 for a method to Hornerize the Berstein polynomials and perhaps produce speedups.


[heading Point types]

The `Point` type must satisfy certain conceptual requirements which are discussed in the documentation of the Catmull-Rom curve.
However, we reiterate them here:

    template<class Real>
    class mypoint3d
    {
    public:
        // Must define a value_type:
        typedef Real value_type;

        // Regular constructor--need not be of this form.
        mypoint3d(Real x, Real y, Real z) {m_vec[0] = x; m_vec[1] = y; m_vec[2] = z; }

        // Must define a default constructor:
        mypoint3d() {}

        // Must define array access:
        Real operator[](size_t i) const
        {
            return m_vec[i];
        }

        // Must define array element assignment:
        Real& operator[](size_t i)
        {
            return m_vec[i];
        }

    private:
        std::array<Real, 3> m_vec;
    };

These conditions are satisfied by both `std::array` and `std::vector`.


[heading References]

* Rainer Kress, ['Numerical Analysis], Springer, 1998
* David Salomon, ['Curves and Surfaces for Computer Graphics], Springer, 2005
* Prautzsch, Hartmut, Wolfgang Boehm, and Marco Paluszny. ['Bézier and B-spline techniques]. Springer Science & Business Media, 2002.

[endsect] [/section:bezier_polynomials Bezier Polynomials]