2 bezier.cc -- implement Bezier and Bezier_bow
4 source file of the GNU LilyPond music typesetter
6 (c) 1998--2001 Jan Nieuwenhuizen <janneke@gnu.org>
13 #include "libc-extension.hh"
15 #include "polynomial.hh"
18 binomial_coefficient (Real over
, int under
)
24 x
*= over
/ Real (under
);
33 scale (Array
<Offset
>* arr_p
, Real x
, Real y
)
35 for (int i
= 0; i
< arr_p
->size (); i
++)
37 (*arr_p
)[i
][X_AXIS
] = x
* (*arr_p
)[i
][X_AXIS
];
38 (*arr_p
)[i
][Y_AXIS
] = y
* (*arr_p
)[i
][Y_AXIS
];
43 rotate (Array
<Offset
>* arr_p
, Real phi
)
45 Offset
rot (complex_exp (Offset (0, phi
)));
46 for (int i
= 0; i
< arr_p
->size (); i
++)
47 (*arr_p
)[i
] = complex_multiply (rot
, (*arr_p
)[i
]);
51 translate (Array
<Offset
>* arr_p
, Offset o
)
53 for (int i
= 0; i
< arr_p
->size (); i
++)
59 Formula of the bezier 3-spline
61 sum_{j=0}^3 (3 over j) z_j (1-t)^ (3-j) t^j
65 Bezier::get_other_coordinate (Axis a
, Real x
) const
67 Axis other
= Axis ((a
+1)%NO_AXES
);
68 Array
<Real
> ts
= solve_point (a
, x
);
72 programming_error ("No solution found for Bezier intersection.");
76 Offset c
= curve_point (ts
[0]);
77 assert (fabs (c
[a
] - x
) < 1e-8);
84 Bezier::curve_point (Real t
)const
87 Real one_min_tj
= (1-t
)* (1-t
)* (1-t
);
90 for (int j
=0 ; j
< 4; j
++)
92 o
+= control_
[j
] * binomial_coefficient (3, j
)
93 * pow (t
,j
) * pow (1-t
, 3-j
);
101 assert (fabs (o
[X_AXIS
] - polynomial (X_AXIS
).eval (t
))< 1e-8);
102 assert (fabs (o
[Y_AXIS
] - polynomial (Y_AXIS
).eval (t
))< 1e-8);
110 Bezier::polynomial (Axis a
)const
113 for (int j
=0; j
<= 3; j
++)
116 * Polynomial::power (j
, Polynomial (0,1))*
117 Polynomial::power (3 - j
, Polynomial (1,-1))*
118 binomial_coefficient (3, j
);
125 Remove all numbers outside [0,1] from SOL
128 filter_solutions (Array
<Real
> sol
)
130 for (int i
= sol
.size (); i
--;)
131 if (sol
[i
] < 0 || sol
[i
] >1)
137 find t such that derivative is proportional to DERIV
140 Bezier::solve_derivative (Offset deriv
)const
142 Polynomial xp
=polynomial (X_AXIS
);
143 Polynomial yp
=polynomial (Y_AXIS
);
147 Polynomial combine
= xp
* deriv
[Y_AXIS
] - yp
* deriv
[X_AXIS
];
149 return filter_solutions (combine
.solve ());
154 Find t such that curve_point (t)[AX] == COORDINATE
157 Bezier::solve_point (Axis ax
, Real coordinate
) const
159 Polynomial
p (polynomial (ax
));
160 p
.coefs_
[0] -= coordinate
;
162 Array
<Real
> sol (p
.solve ());
163 return filter_solutions (sol
);
167 Compute the bounding box dimensions in direction of A.
170 Bezier::extent (Axis a
)const
172 int o
= (a
+1)%NO_AXES
;
176 Array
<Real
> sols (solve_derivative (d
));
179 for (int i
= sols
.size (); i
--;)
181 Offset
o (curve_point (sols
[i
]));
182 iv
.unite (Interval (o
[a
],o
[a
]));
192 Bezier::scale (Real x
, Real y
)
194 for (int i
= CONTROL_COUNT
; i
--;)
196 control_
[i
][X_AXIS
] = x
* control_
[i
][X_AXIS
];
197 control_
[i
][Y_AXIS
] = y
* control_
[i
][Y_AXIS
];
202 Bezier::rotate (Real phi
)
204 Offset
rot (complex_exp (Offset (0, phi
)));
205 for (int i
= 0; i
< CONTROL_COUNT
; i
++)
206 control_
[i
] = complex_multiply (rot
, control_
[i
]);
210 Bezier::translate (Offset o
)
212 for (int i
= 0; i
< CONTROL_COUNT
; i
++)
217 Bezier::assert_sanity () const
219 for (int i
=0; i
< CONTROL_COUNT
; i
++)
220 assert (!isnan (control_
[i
].length ())
221 && !isinf (control_
[i
].length ()));
228 for (int i
=0; i
< CONTROL_COUNT
; i
++)
229 b2
.control_
[CONTROL_COUNT
-i
-1] = control_
[i
];