# curve module

This is a collection of procedures for performing computations on a Bézier curve.

## Procedures

void BEZ_compute_length(const int *num_nodes, const int *dimension, const double *nodes, double *length, int *error_val)

Computes the length of a Bézier curve via

$\ell = \int_0^1 \left\lVert B'(s) \right\rVert \, ds.$
Parameters:
• num_nodes (const int*) – [Input] The number of control points $$N$$ of a Bézier curve.

• dimension (const int*) – [Input] The dimension $$D$$ such that the curve lies in $$\mathbf{R}^D$$.

• nodes (const double*) – [Input] The actual control points of the curve as a $$D \times N$$ array. This should be laid out in Fortran order, with $$D N$$ total values.

• length (double*) – [Output] The computed length $$\ell$$.

• error_val (int*) – [Output] An error status passed along from dqagse (a QUADPACK procedure).

Signature:

void
BEZ_compute_length(const int *num_nodes,
const int *dimension,
const double *nodes,
double *length,
int *error_val);


Example:

// Inputs.
int num_nodes = 2;
int dimension = 2;
double nodes[4] = { 0.0, 0.0, 3.0, 4.0 };

// Outputs.
double length;
int error_val;

BEZ_compute_length(&num_nodes, &dimension, nodes, &length, &error_val);
printf("Length: %f\n", length);
printf("Error value: %d\n", error_val);


Consider the line segment $$B(s) = \left[\begin{array}{c} 3s \\ 4s \end{array}\right]$$, we can verify the length:

$INCLUDE_DIR=.../libbezier-release/usr/include$ LIB_DIR=.../libbezier-release/usr/lib
$gcc \ > -o example \ > example_compute_length.c \ > -I "${INCLUDE_DIR}" \
>     -L "${LIB_DIR}" \ > -Wl,-rpath,"${LIB_DIR}" \
>     -lbezier \
>     -lm -lgfortran
$./example Length: 5.000000 Error value: 0  void BEZ_elevate_nodes_curve(const int *num_nodes, const int *dimension, const double *nodes, double *elevated) Degree-elevate a Bézier curve. Does so by producing control points of a higher degree that define the exact same curve. See Curve.elevate() for more details. Parameters: • num_nodes (const int*) – [Input] The number of control points $$N$$ of a Bézier curve. • dimension (const int*) – [Input] The dimension $$D$$ such that the curve lies in $$\mathbf{R}^D$$. • nodes (const double*) – [Input] The actual control points of the curve as a $$D \times N$$ array. This should be laid out in Fortran order, with $$D N$$ total values. • elevated (double*) – [Output] The control points of the degree-elevated curve as a $$D \times (N + 1)$$ array, laid out in Fortran order. Signature: void BEZ_elevate_nodes_curve(const int *num_nodes, const int *dimension, const double *nodes, double *elevated);  Example: After elevating $$B(s) = \left[\begin{array}{c} 0 \\ 0 \end{array}\right] (1 - s)^2 + \frac{1}{2} \left[\begin{array}{c} 3 \\ 3 \end{array}\right] 2 (1 - s) s + \left[\begin{array}{c} 3 \\ 0 \end{array}\right] s^2$$: // Inputs. int num_nodes = 3; int dimension = 2; double nodes[6] = { 0.0, 0.0, 1.5, 1.5, 3.0, 0.0 }; // Outputs. double elevated[8]; BEZ_elevate_nodes_curve(&num_nodes, &dimension, nodes, elevated); printf("Elevated:\n"); printf("%f, %f, %f, %f\n", elevated[0], elevated[2], elevated[4], elevated[6]); printf("%f, %f, %f, %f\n", elevated[1], elevated[3], elevated[5], elevated[7]);  we have $$B(s) = \left[\begin{array}{c} 0 \\ 0 \end{array}\right] (1 - s)^3 + \left[\begin{array}{c} 1 \\ 1 \end{array}\right] 3 (1 - s)^2 s + \left[\begin{array}{c} 2 \\ 1 \end{array}\right] 3 (1 - s) s^2 + \left[\begin{array}{c} 3 \\ 0 \end{array}\right] s^3$$: $ INCLUDE_DIR=.../libbezier-release/usr/include
$LIB_DIR=.../libbezier-release/usr/lib$ gcc \
>     -o example \
>     example_elevate_nodes_curve.c \
>     -I "${INCLUDE_DIR}" \ > -L "${LIB_DIR}" \
>     -Wl,-rpath,"${LIB_DIR}" \ > -lbezier \ > -lm -lgfortran$ ./example
Elevated:
0.000000, 1.000000, 2.000000, 3.000000
0.000000, 1.000000, 1.000000, 0.000000

void BEZ_evaluate_curve_barycentric(const int *num_nodes, const int *dimension, const double *nodes, const int *num_vals, const double *lambda1, const double *lambda2, double *evaluated)

For a Bézier curve with control points $$p_0, \ldots, p_d$$, this evaluates the quantity

$Q(\lambda_1, \lambda_2) = \sum_{j = 0}^d \binom{d}{j} \lambda_1^{d - j} \lambda_2^j p_j.$

The typical case is barycentric, i.e. $$\lambda_1 + \lambda_2 = 1$$, but this is not required.

Parameters:
• num_nodes (const int*) – [Input] The number of control points $$N$$ of a Bézier curve.

• dimension (const int*) – [Input] The dimension $$D$$ such that the curve lies in $$\mathbf{R}^D$$.

• nodes (const double*) – [Input] The actual control points of the curve as a $$D \times N$$ array. This should be laid out in Fortran order, with $$D N$$ total values.

• num_vals (const int*) – [Input] The number of values $$k$$ where the quantity will be evaluated.

• lambda1 (const double*) – [Input] An array of $$k$$ values used for the first parameter $$\lambda_1$$.

• lambda2 (const double*) – [Input] An array of $$k$$ values used for the second parameter $$\lambda_2$$.

• evaluated (double*) – [Output] The evaluated quantites as a $$D \times k$$ array, laid out in Fortran order. Column $$j$$ of evaluated will contain $$Q\left(\lambda_1\left[j\right], \lambda_2\left[j\right]\right)$$.

Signature:

void
BEZ_evaluate_curve_barycentric(const int *num_nodes,
const int *dimension,
const double *nodes,
const int *num_vals,
const double *lambda1,
const double *lambda2,
double *evaluated);


Example:

For the curve $$B(s) = \left[\begin{array}{c} 0 \\ 1 \end{array}\right] (1 - s)^2 + \left[\begin{array}{c} 2 \\ 1 \end{array}\right] 2 (1 - s) s + \left[\begin{array}{c} 3 \\ 3 \end{array}\right] s^2 = \left[\begin{array}{c} s(4 - s) \\ 2s^2 + 1 \end{array}\right]$$:

// Inputs.
int num_nodes = 3;
int dimension = 2;
double nodes[6] = { 0.0, 1.0, 2.0, 1.0, 3.0, 3.0 };
int num_vals = 4;
double lambda1[4] = { 0.25, 0.5, 0.0, 1.0 };
double lambda2[4] = { 0.75, 0.25, 0.5, 0.25 };

// Outputs.
double evaluated[8];

BEZ_evaluate_curve_barycentric(
&num_nodes, &dimension, nodes, &num_vals, lambda1, lambda2, evaluated);
printf("Evaluated:\n");
printf("%f, %f, %f, %f\n", evaluated[0], evaluated[2], evaluated[4],
evaluated[6]);
printf("%f, %f, %f, %f\n", evaluated[1], evaluated[3], evaluated[5],
evaluated[7]);


we have

\begin{split}\begin{align*} Q\left(\frac{1}{4}, \frac{3}{4}\right) &= \frac{1}{16} \left[ \begin{array}{c} 39 \\ 34 \end{array}\right] \\ Q\left(\frac{1}{2}, \frac{1}{4}\right) &= \frac{1}{16} \left[ \begin{array}{c} 11 \\ 11 \end{array}\right] \\ Q\left(0, \frac{1}{2}\right) &= \frac{1}{4} \left[ \begin{array}{c} 3 \\ 3 \end{array}\right] \\ Q\left(1, \frac{1}{4}\right) &= \frac{1}{16} \left[ \begin{array}{c} 19 \\ 27 \end{array}\right] \end{align*}\end{split}
$INCLUDE_DIR=.../libbezier-release/usr/include$ LIB_DIR=.../libbezier-release/usr/lib
$gcc \ > -o example \ > example_evaluate_curve_barycentric.c \ > -I "${INCLUDE_DIR}" \
>     -L "${LIB_DIR}" \ > -Wl,-rpath,"${LIB_DIR}" \
>     -lbezier \
>     -lm -lgfortran
$./example Evaluated: 2.437500, 0.687500, 0.750000, 1.187500 2.125000, 0.687500, 0.750000, 1.687500  void BEZ_evaluate_hodograph(const double *s, const int *num_nodes, const int *dimension, const double *nodes, double *hodograph) Evaluates the hodograph (or derivative) of a Bézier curve function $$B'(s)$$. Parameters: • s (const double*) – [Input] The parameter $$s$$ where the hodograph is being computed. • num_nodes (const int*) – [Input] The number of control points $$N$$ of a Bézier curve. • dimension (const int*) – [Input] The dimension $$D$$ such that the curve lies in $$\mathbf{R}^D$$. • nodes (const double*) – [Input] The actual control points of the curve as a $$D \times N$$ array. This should be laid out in Fortran order, with $$D N$$ total values. • hodograph (double*) – [Output] The hodograph $$B'(s)$$ as a $$D \times 1$$ array. Signature: void BEZ_evaluate_hodograph(const double *s, const int *num_nodes, const int *dimension, const double *nodes, double *hodograph);  Example: For the curve $$B(s) = \left[\begin{array}{c} 1 \\ 0 \end{array}\right] (1 - s)^3 + \left[\begin{array}{c} 1 \\ 1 \end{array}\right] 3 (1 - s)^2 s + \left[\begin{array}{c} 2 \\ 0 \end{array}\right] 3 (1 - s) s^2 + \left[\begin{array}{c} 2 \\ 1 \end{array}\right] s^3$$: // Inputs. double s = 0.125; int num_nodes = 4; int dimension = 2; double nodes[8] = { 1.0, 0.0, 1.0, 1.0, 2.0, 0.0, 2.0, 1.0 }; // Outputs. double hodograph[2]; BEZ_evaluate_hodograph(&s, &num_nodes, &dimension, nodes, hodograph); printf("Hodograph:\n%f\n%f\n", hodograph[0], hodograph[1]);  we have $$B'\left(\frac{1}{8}\right) = \frac{1}{32} \left[ \begin{array}{c} 21 \\ 54 \end{array}\right]$$: $ INCLUDE_DIR=.../libbezier-release/usr/include
$LIB_DIR=.../libbezier-release/usr/lib$ gcc \
>     -o example \
>     example_evaluate_hodograph.c \
>     -I "${INCLUDE_DIR}" \ > -L "${LIB_DIR}" \
>     -Wl,-rpath,"${LIB_DIR}" \ > -lbezier \ > -lm -lgfortran$ ./example
Hodograph:
0.656250
1.687500

void BEZ_evaluate_multi(const int *num_nodes, const int *dimension, const double *nodes, const int *num_vals, const double *s_vals, double *evaluated)

Evaluate a Bézier curve function $$B(s_j)$$ at multiple values $$\left\{s_j\right\}_j$$.

Parameters:
• num_nodes (const int*) – [Input] The number of control points $$N$$ of a Bézier curve.

• dimension (const int*) – [Input] The dimension $$D$$ such that the curve lies in $$\mathbf{R}^D$$.

• nodes (const double*) – [Input] The actual control points of the curve as a $$D \times N$$ array. This should be laid out in Fortran order, with $$D N$$ total values.

• num_vals (const int*) – [Input] The number of values $$k$$ where the $$B(s)$$ will be evaluated.

• s_vals (const double*) – [Input] An array of $$k$$ values $$s_j$$.

• evaluated (double*) – [Output] The evaluated points as a $$D \times k$$ array, laid out in Fortran order. Column $$j$$ of evaluated will contain $$B\left(s_j\right)$$.

Signature:

void
BEZ_evaluate_multi(const int *num_nodes,
const int *dimension,
const double *nodes,
const int *num_vals,
const double *s_vals,
double *evaluated);


Example:

For the curve $$B(s) = \left[\begin{array}{c} 1 \\ 0 \end{array}\right] (1 - s)^3 + \left[\begin{array}{c} 1 \\ 1 \end{array}\right] 3 (1 - s)^2 s + \left[\begin{array}{c} 2 \\ 0 \end{array}\right] 3 (1 - s) s^2 + \left[\begin{array}{c} 2 \\ 1 \end{array}\right] s^3$$:

// Inputs.
int num_nodes = 4;
int dimension = 2;
double nodes[8] = { 1.0, 0.0, 1.0, 1.0, 2.0, 0.0, 2.0, 1.0 };
int num_vals = 3;
double s_vals[3] = { 0.0, 0.5, 1.0 };

// Outputs.
double evaluated[6];

BEZ_evaluate_multi(
&num_nodes, &dimension, nodes, &num_vals, s_vals, evaluated);
printf("Evaluated:\n");
printf("%f, %f, %f\n", evaluated[0], evaluated[2], evaluated[4]);
printf("%f, %f, %f\n", evaluated[1], evaluated[3], evaluated[5]);


we have $$B\left(0\right) = \left[\begin{array}{c} 1 \\ 0 \end{array}\right], B\left(\frac{1}{2}\right) = \frac{1}{2} \left[\begin{array}{c} 3 \\ 1 \end{array}\right]$$ and $$B\left(1\right) = \left[\begin{array}{c} 2 \\ 1 \end{array}\right]$$:

$INCLUDE_DIR=.../libbezier-release/usr/include$ LIB_DIR=.../libbezier-release/usr/lib
$gcc \ > -o example \ > example_evaluate_multi.c \ > -I "${INCLUDE_DIR}" \
>     -L "${LIB_DIR}" \ > -Wl,-rpath,"${LIB_DIR}" \
>     -lbezier \
>     -lm -lgfortran
$./example Evaluated: 1.000000, 1.500000, 2.000000 0.000000, 0.500000, 1.000000  void BEZ_full_reduce(const int *num_nodes, const int *dimension, const double *nodes, const int *num_reduced_nodes, double *reduced, bool *not_implemented) Perform a “full” degree reduction. Does so by using BEZ_reduce_pseudo_inverse() continually until the degree of the curve can no longer be reduced. Parameters: • num_nodes (const int*) – [Input] The number of control points $$N$$ of a Bézier curve. • dimension (const int*) – [Input] The dimension $$D$$ such that the curve lies in $$\mathbf{R}^D$$. • nodes (const double*) – [Input] The actual control points of the curve as a $$D \times N$$ array. This should be laid out in Fortran order, with $$D N$$ total values. • num_reduced_nodes (const int*) – [Output] The number of control points $$M$$ of the fully reduced curve. • reduced (double*) – [Output] The control points of the fully reduced curve as a $$D \times N$$ array. The first $$M$$ columns will contain the reduced nodes. reduced must be allocated by the caller and since $$M = N$$ occurs when no reduction is possible, this array must be $$D \times N$$. • not_implemented (bool*) – [Output] Indicates if degree-reduction has been implemented for the current curve’s degree. (Currently, the only degrees supported are 1, 2, 3 and 4.) Signature: void BEZ_full_reduce(const int *num_nodes, const int *dimension, const double *nodes, const int *num_reduced_nodes, double *reduced, bool *not_implemented);  Example: When taking a curve that is degree-elevated from linear to quartic: // Inputs. int num_nodes = 5; int dimension = 2; double nodes[10] = { 1.0, 3.0, 1.25, 3.5, 1.5, 4.0, 1.75, 4.5, 2.0, 5.0 }; // Outputs. int num_reduced_nodes; double reduced[10]; bool not_implemented; BEZ_full_reduce(&num_nodes, &dimension, nodes, &num_reduced_nodes, reduced, &not_implemented); printf("Number of reduced nodes: %d\n", num_reduced_nodes); printf("Reduced:\n"); printf("%f, %f\n", reduced[0], reduced[2]); printf("%f, %f\n", reduced[1], reduced[3]); printf("Not implemented: %s\n", not_implemented ? "TRUE" : "FALSE");  this procedure reduces it to the line $$B(s) = \left[\begin{array}{c} 1 \\ 3 \end{array}\right] (1 - s) + \left[\begin{array}{c} 2 \\ 5 \end{array}\right] s = \left[\begin{array}{c} 1 + s \\ 3 + 2s \end{array}\right]$$: $ INCLUDE_DIR=.../libbezier-release/usr/include
$LIB_DIR=.../libbezier-release/usr/lib$ gcc \
>     -o example \
>     example_full_reduce.c \
>     -I "${INCLUDE_DIR}" \ > -L "${LIB_DIR}" \
>     -Wl,-rpath,"${LIB_DIR}" \ > -lbezier \ > -lm -lgfortran$ ./example
Number of reduced nodes: 2
Reduced:
1.000000, 2.000000
3.000000, 5.000000
Not implemented: FALSE

void BEZ_get_curvature(const int *num_nodes, const double *nodes, const double *tangent_vec, const double *s, double *curvature)

Get the signed curvature of a Bézier curve at a point. See hazmat.curve_helpers.get_curvature() for more details.

Note

This only computes curvature for plane curves (i.e. curves in $$\mathbf{R}^2$$). An equivalent notion of curvature exists for space curves, but support for that is not implemented here.

Parameters:
• num_nodes (const int*) – [Input] The number of control points $$N$$ of a Bézier curve.

• nodes (const double*) – [Input] The actual control points of the curve as a $$2 \times N$$ array. This should be laid out in Fortran order, with $$2 N$$ total values.

• tangent_vec (const double*) – [Input] The hodograph $$B'(s)$$ as a $$2 \times 1$$ array. Note that this could be computed once $$s$$ and $$B$$ are known, but this allows the caller to re-use an already computed tangent vector.

• s (const double*) – [Input] The parameter $$s$$ where the curvature is being computed.

• curvature (double*) – [Output] The signed curvature $$\kappa$$.

Signature:

void
BEZ_get_curvature(const int *num_nodes,
const double *nodes,
const double *tangent_vec,
const double *s,
double *curvature);


Example:

// Inputs.
int num_nodes = 5;
double nodes[10] = { 1.0, 0.0, 0.75, 2.0, 0.5, -2.0, 0.25, 2.0, 0.0, 0.0 };
double tangent_vec[2] = { -1.0, 0.0 };
double s = 0.5;

// Outputs.
double curvature;

BEZ_get_curvature(&num_nodes, nodes, tangent_vec, &s, &curvature);
printf("Curvature: %f\n", curvature);

$INCLUDE_DIR=.../libbezier-release/usr/include$ LIB_DIR=.../libbezier-release/usr/lib
$gcc \ > -o example \ > example_get_curvature.c \ > -I "${INCLUDE_DIR}" \
>     -L "${LIB_DIR}" \ > -Wl,-rpath,"${LIB_DIR}" \
>     -lbezier \
>     -lm -lgfortran
$./example Curvature: -12.000000  void BEZ_locate_point_curve(const int *num_nodes, const int *dimension, const double *nodes, const double *point, double *s_approx) This solves the inverse problem $$B(s) = p$$ (if it can be solved). Does so by subdividing the curve until the segments are sufficiently small, then using Newton’s method to narrow in on the pre-image of the point. Parameters: • num_nodes (const int*) – [Input] The number of control points $$N$$ of a Bézier curve. • dimension (const int*) – [Input] The dimension $$D$$ such that the curve lies in $$\mathbf{R}^D$$. • nodes (const double*) – [Input] The actual control points of the curve as a $$D \times N$$ array. This should be laid out in Fortran order, with $$D N$$ total values. • point (const double*) – [Input] The point $$p$$ as a $$D \times 1$$ array. • s_approx (double*) – [Output] The parameter $$s$$ of the solution. If $$p$$ can’t be located on the curve, then s_approx = -1.0. If there are multiple parameters that satisfy $$B(s) = p$$ (indicating that $$B(s)$$ has a self-crossing) then s_approx = -2.0. Signature: void BEZ_locate_point_curve(const int *num_nodes, const int *dimension, const double *nodes, const double *point, double *s_approx);  Example: For $$B(s) = \left[\begin{array}{c} 0 \\ 2 \end{array}\right] (1 - s)^3 + \left[\begin{array}{c} -1 \\ 0 \end{array}\right] 3 (1 - s)^2 s + \left[\begin{array}{c} 1 \\ 1 \end{array}\right] 3 (1 - s) s^2 + \frac{1}{8} \left[\begin{array}{c} -6 \\ 13 \end{array}\right] s^3$$: // Inputs. int num_nodes = 4; int dimension = 2; double nodes[8] = { 0.0, 2.0, -1.0, 0.0, 1.0, 1.0, -0.75, 1.625 }; double point1[2] = { -0.09375, 0.828125 }; double point2[2] = { 0.0, 1.5 }; double point3[2] = { -0.25, 1.375 }; // Outputs. double s_approx; BEZ_locate_point_curve(&num_nodes, &dimension, nodes, point1, &s_approx); printf("When B(s) = [% f, %f]; s = % f\n", point1[0], point1[1], s_approx); BEZ_locate_point_curve(&num_nodes, &dimension, nodes, point2, &s_approx); printf("When B(s) = [% f, %f]; s = % f\n", point2[0], point2[1], s_approx); BEZ_locate_point_curve(&num_nodes, &dimension, nodes, point3, &s_approx); printf("When B(s) = [% f, %f]; s = % f\n", point3[0], point3[1], s_approx);  We can locate the point $$B\left(\frac{1}{2}\right) = \frac{1}{64} \left[\begin{array}{c} -6 \\ 53 \end{array}\right]$$ but find that $$\frac{1}{2} \left[\begin{array}{c} 0 \\ 3 \end{array}\right]$$ is not on the curve and that $\begin{split}B\left(\frac{3 - \sqrt{5}}{6}\right) = B\left(\frac{3 + \sqrt{5}}{6}\right) = \frac{1}{8} \left[ \begin{array}{c} -2 \\ 11 \end{array}\right]\end{split}$ is a self-crossing: $ INCLUDE_DIR=.../libbezier-release/usr/include
$LIB_DIR=.../libbezier-release/usr/lib$ gcc \
>     -o example \
>     example_locate_point_curve.c \
>     -I "${INCLUDE_DIR}" \ > -L "${LIB_DIR}" \
>     -Wl,-rpath,"${LIB_DIR}" \ > -lbezier \ > -lm -lgfortran$ ./example
When B(s) = [-0.093750, 0.828125]; s =  0.500000
When B(s) = [ 0.000000, 1.500000]; s = -1.000000
When B(s) = [-0.250000, 1.375000]; s = -2.000000

void BEZ_newton_refine_curve(const int *num_nodes, const int *dimension, const double *nodes, const double *point, const double *s, double *updated_s)

This refines a solution to $$B(s) = p$$ using Newton’s method. Given a current approximation $$s_n$$ for a solution, this produces the updated approximation via

$s_{n + 1} = s_n - \frac{B'(s_n)^T \left[B(s_n) - p\right]}{ B'(s_n)^T B'(s_n)}.$
Parameters:
• num_nodes (const int*) – [Input] The number of control points $$N$$ of a Bézier curve.

• dimension (const int*) – [Input] The dimension $$D$$ such that the curve lies in $$\mathbf{R}^D$$.

• nodes (const double*) – [Input] The actual control points of the curve as a $$D \times N$$ array. This should be laid out in Fortran order, with $$D N$$ total values.

• point (const double*) – [Input] The point $$p$$ as a $$D \times 1$$ array.

• s (const double*) – [Input] The parameter $$s_n$$ of the current approximation of a solution.

• updated_s (double*) – [Output] The parameter $$s_{n + 1}$$ of the updated approximation.

Signature:

void
BEZ_newton_refine_curve(const int *num_nodes,
const int *dimension,
const double *nodes,
const double *point,
const double *s,
double *updated_s);


Example:

When trying to locate $$B\left(\frac{1}{4}\right) = \frac{1}{16} \left[\begin{array}{c} 9 \\ 13 \end{array}\right]$$ on the curve $$B(s) = \left[\begin{array}{c} 0 \\ 0 \end{array}\right] (1 - s)^2 + \left[\begin{array}{c} 1 \\ 2 \end{array}\right] 2 (1 - s) s + \left[\begin{array}{c} 3 \\ 1 \end{array}\right] s^2$$, starting at $$s = \frac{3}{4}$$:

// Inputs.
int num_nodes = 3;
int dimension = 2;
double nodes[6] = { 0.0, 0.0, 1.0, 2.0, 3.0, 1.0 };
double point[2] = { 0.5625, 0.8125 };
double s = 0.75;

// Outputs.
double updated_s;

BEZ_newton_refine_curve(
&num_nodes, &dimension, nodes, point, &s, &updated_s);


we expect a Newton update $$\Delta s = -\frac{2}{5}$$, which produces a new parameter value $$s = \frac{7}{20}$$:

$INCLUDE_DIR=.../libbezier-release/usr/include$ LIB_DIR=.../libbezier-release/usr/lib
$gcc \ > -o example \ > example_newton_refine_curve.c \ > -I "${INCLUDE_DIR}" \
>     -L "${LIB_DIR}" \ > -Wl,-rpath,"${LIB_DIR}" \
>     -lbezier \
>     -lm -lgfortran
$./example Updated s: 0.350000  void BEZ_reduce_pseudo_inverse(const int *num_nodes, const int *dimension, const double *nodes, double *reduced, bool *not_implemented) Perform a pseudo inverse to BEZ_elevate_nodes_curve(). If an inverse can be found, i.e. if a curve can be degree-reduced, then this will produce the equivalent curve of lower degree. If no inverse can be found, then this will produce the “best” answer in the least squares sense. Parameters: • num_nodes (const int*) – [Input] The number of control points $$N$$ of a Bézier curve. • dimension (const int*) – [Input] The dimension $$D$$ such that the curve lies in $$\mathbf{R}^D$$. • nodes (const double*) – [Input] The actual control points of the curve as a $$D \times N$$ array. This should be laid out in Fortran order, with $$D N$$ total values. • reduced (double*) – [Output] The control points of the degree-(pseudo)reduced curve $$D \times (N - 1)$$ array, laid out in Fortran order. • not_implemented (bool*) – [Output] Indicates if degree-reduction has been implemented for the current curve’s degree. (Currently, the only degrees supported are 1, 2, 3 and 4.) Signature: void BEZ_reduce_pseudo_inverse(const int *num_nodes, const int *dimension, const double *nodes, double *reduced, bool *not_implemented);  Example: After reducing $$B(s) = \left[\begin{array}{c} -3 \\ 3 \end{array}\right] (1 - s)^3 + \left[\begin{array}{c} 0 \\ 2 \end{array}\right] 3 (1 - s)^2 s + \left[\begin{array}{c} 1 \\ 3 \end{array}\right] 3 (1 - s) s^2 + \left[\begin{array}{c} 0 \\ 6 \end{array}\right] s^3$$: // Inputs. int num_nodes = 4; int dimension = 2; double nodes[8] = { -3.0, 3.0, 0.0, 2.0, 1.0, 3.0, 0.0, 6.0 }; // Outputs. double reduced[6]; bool not_implemented; BEZ_reduce_pseudo_inverse( &num_nodes, &dimension, nodes, reduced, &not_implemented); printf("Reduced:\n"); printf("% f, %f, %f\n", reduced[0], reduced[2], reduced[4]); printf("% f, %f, %f\n", reduced[1], reduced[3], reduced[5]); printf("Not implemented: %s\n", not_implemented ? "TRUE" : "FALSE");  we get the valid quadratic representation of $$B(s) = \left[\begin{array}{c} 3(1 - s)(2s - 1) \\ 3(2s^2 - s + 1) \end{array}\right]$$: $ INCLUDE_DIR=.../libbezier-release/usr/include
$LIB_DIR=.../libbezier-release/usr/lib$ gcc \
>     -o example \
>     example_reduce_pseudo_inverse.c \
>     -I "${INCLUDE_DIR}" \ > -L "${LIB_DIR}" \
>     -Wl,-rpath,"${LIB_DIR}" \ > -lbezier \ > -lm -lgfortran$ ./example
Reduced:
-3.000000, 1.500000, 0.000000
3.000000, 1.500000, 6.000000
Not implemented: FALSE

void BEZ_specialize_curve(const int *num_nodes, const int *dimension, const double *nodes, const double *start, const double *end, double *new_nodes)

Specialize a Bézier curve to an interval $$\left[a, b\right]$$. This produces the control points for the curve given by $$B\left(a + (b - a) s\right)$$.

Parameters:
• num_nodes (const int*) – [Input] The number of control points $$N$$ of a Bézier curve.

• dimension (const int*) – [Input] The dimension $$D$$ such that the curve lies in $$\mathbf{R}^D$$.

• nodes (const double*) – [Input] The actual control points of the curve as a $$D \times N$$ array. This should be laid out in Fortran order, with $$D N$$ total values.

• start (const double*) – [Input] The start $$a$$ of the specialized interval.

• end (const double*) – [Input] The end $$b$$ of the specialized interval.

• new_nodes (double*) – [Output] The control points of the specialized curve, as a $$D \times N$$ array, laid out in Fortran order.

Signature:

void
BEZ_specialize_curve(const int *num_nodes,
const int *dimension,
const double *nodes,
const double *start,
const double *end,
double *new_nodes);


Example:

When we specialize the curve $$B(s) = \left[\begin{array}{c} 0 \\ 0 \end{array}\right] (1 - s)^2 + \frac{1}{2} \left[\begin{array}{c} 1 \\ 2 \end{array}\right] 2 (1 - s) s + \left[\begin{array}{c} 1 \\ 0 \end{array}\right] s^2 = \left[\begin{array}{c} s \\ 2s(1 - s) \end{array}\right]$$ to the interval $$\left[-\frac{1}{4}, \frac{3}{4}\right]$$:

// Inputs.
int num_nodes = 3;
int dimension = 2;
double nodes[6] = { 0.0, 0.0, 0.5, 1.0, 1.0, 0.0 };
double start = -0.25;
double end = 0.75;

// Outputs.
double new_nodes[6];

BEZ_specialize_curve(
&num_nodes, &dimension, nodes, &start, &end, new_nodes);
printf("New Nodes:\n");
printf("%f, %f, %f\n", new_nodes[0], new_nodes[2], new_nodes[4]);


we get the specialized curve $$S(t) = \frac{1}{8} \left[ \begin{array}{c} -2 \\ -5 \end{array}\right] (1 - s)^2 + \frac{1}{8} \left[\begin{array}{c} 2 \\ 7 \end{array}\right] 2 (1 - s) s + \frac{1}{8} \left[\begin{array}{c} 6 \\ 3 \end{array}\right] s^2 = \frac{1}{8} \left[\begin{array}{c} 2(4t - 1) \\ (4t - 1)(5 - 4t) \end{array}\right]$$, which still lies on $$y = 2x(1 - x)$$:

$INCLUDE_DIR=.../libbezier-release/usr/include$ LIB_DIR=.../libbezier-release/usr/lib
$gcc \ > -o example \ > example_specialize_curve.c \ > -I "${INCLUDE_DIR}" \
>     -L "${LIB_DIR}" \ > -Wl,-rpath,"${LIB_DIR}" \
>     -lbezier \
>     -lm -lgfortran
$./example New Nodes: -0.250000, 0.250000, 0.750000 -0.625000, 0.875000, 0.375000  void BEZ_subdivide_nodes_curve(const int *num_nodes, const int *dimension, const double *nodes, double *left_nodes, double *right_nodes) Split a Bézier curve into two halves $$B\left(\left[0, \frac{1}{2}\right]\right)$$ and $$B\left(\left[\frac{1}{2}, 1\right]\right)$$. Parameters: • num_nodes (const int*) – [Input] The number of control points $$N$$ of a Bézier curve. • dimension (const int*) – [Input] The dimension $$D$$ such that the curve lies in $$\mathbf{R}^D$$. • nodes (const double*) – [Input] The actual control points of the curve as a $$D \times N$$ array. This should be laid out in Fortran order, with $$D N$$ total values. • left_nodes (double*) – [Output] The control points of the left half curve $$B\left(\left[0, \frac{1}{2}\right]\right)$$ as a $$D \times N$$ array, laid out in Fortran order. • right_nodes (double*) – [Output] The control points of the right half curve $$B\left(\left[\frac{1}{2}, 1\right]\right)$$ as a $$D \times N$$ array, laid out in Fortran order. Signature: void BEZ_subdivide_nodes_curve(const int *num_nodes, const int *dimension, const double *nodes, double *left_nodes, double *right_nodes);  Example: For example, subdividing the curve $$B(s) = \left[\begin{array}{c} 0 \\ 0 \end{array}\right] (1 - s)^2 + \frac{1}{4} \left[\begin{array}{c} 5 \\ 12 \end{array}\right] 2 (1 - s) s + \left[\begin{array}{c} 2 \\ 1 \end{array}\right] s^2$$: // Inputs. int num_nodes = 3; int dimension = 2; double nodes[6] = { 0.0, 0.0, 1.25, 3.0, 2.0, 1.0 }; // Outputs. double left_nodes[6]; double right_nodes[6]; BEZ_subdivide_nodes_curve( &num_nodes, &dimension, nodes, left_nodes, right_nodes); printf("Left Nodes:\n"); printf("%f, %f, %f\n", left_nodes[0], left_nodes[2], left_nodes[4]); printf("%f, %f, %f\n", left_nodes[1], left_nodes[3], left_nodes[5]); printf("Right Nodes:\n"); printf("%f, %f, %f\n", right_nodes[0], right_nodes[2], right_nodes[4]); printf("%f, %f, %f\n", right_nodes[1], right_nodes[3], right_nodes[5]);  yields: $ INCLUDE_DIR=.../libbezier-release/usr/include
$LIB_DIR=.../libbezier-release/usr/lib$ gcc \
>     -o example \
>     example_subdivide_nodes_curve.c \
>     -I "${INCLUDE_DIR}" \ > -L "${LIB_DIR}" \
>     -Wl,-rpath,"${LIB_DIR}" \ > -lbezier \ > -lm -lgfortran$ ./example
Left Nodes:
0.000000, 0.625000, 1.125000
0.000000, 1.500000, 1.750000
Right Nodes:
1.125000, 1.625000, 2.000000
1.750000, 2.000000, 1.000000