2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 1998--2010 Jan Nieuwenhuizen <janneke@gnu.org>
6 LilyPond is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 LilyPond is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
22 #include "libc-extension.hh"
24 Real binomial_coefficient_3
[] = {
29 scale (vector
<Offset
> *array
, Real x
, Real y
)
31 for (vsize i
= 0; i
< array
->size (); i
++)
33 (*array
)[i
][X_AXIS
] = x
* (*array
)[i
][X_AXIS
];
34 (*array
)[i
][Y_AXIS
] = y
* (*array
)[i
][Y_AXIS
];
39 rotate (vector
<Offset
> *array
, Real phi
)
41 Offset
rot (complex_exp (Offset (0, phi
)));
42 for (vsize i
= 0; i
< array
->size (); i
++)
43 (*array
)[i
] = complex_multiply (rot
, (*array
)[i
]);
47 translate (vector
<Offset
> *array
, Offset o
)
49 for (vsize i
= 0; i
< array
->size (); i
++)
54 Formula of the bezier 3-spline
56 sum_{j = 0}^3 (3 over j) z_j (1-t)^ (3-j) t^j
59 A is the axis of X coordinate.
63 Bezier::get_other_coordinate (Axis a
, Real x
) const
65 Axis other
= Axis ((a
+1) % NO_AXES
);
66 vector
<Real
> ts
= solve_point (a
, x
);
70 programming_error ("no solution found for Bezier intersection");
75 Offset c
= curve_point (ts
[0]);
76 if (fabs (c
[a
] - x
) > 1e-8)
77 programming_error ("bezier intersection not correct?");
80 return curve_coordinate (ts
[0], other
);
84 Bezier::curve_coordinate (Real t
, Axis a
) const
89 for (int i
= 1; i
< 4; i
++)
90 one_min_tj
[i
] = one_min_tj
[i
- 1] * (1 - t
);
93 for (int j
= 0; j
< 4; j
++)
95 r
+= control_
[j
][a
] * binomial_coefficient_3
[j
]
96 * tj
* one_min_tj
[3 - j
];
105 Bezier::curve_point (Real t
) const
110 for (int i
= 1; i
< 4; i
++)
111 one_min_tj
[i
] = one_min_tj
[i
- 1] * (1 - t
);
114 for (int j
= 0; j
< 4; j
++)
116 o
+= control_
[j
] * binomial_coefficient_3
[j
]
117 * tj
* one_min_tj
[3 - j
];
123 assert (fabs (o
[X_AXIS
] - polynomial (X_AXIS
).eval (t
)) < 1e-8);
124 assert (fabs (o
[Y_AXIS
] - polynomial (Y_AXIS
).eval (t
)) < 1e-8);
131 Cache binom (3, j) t^j (1-t)^{3-j}
133 struct Polynomial_cache
{
134 Polynomial terms_
[4];
137 for (int j
= 0; j
<= 3; j
++)
139 = binomial_coefficient_3
[j
]
140 * Polynomial::power (j
, Polynomial (0, 1))
141 * Polynomial::power (3 - j
, Polynomial (1, -1));
145 static Polynomial_cache poly_cache
;
148 Bezier::polynomial (Axis a
) const
152 for (int j
= 0; j
<= 3; j
++)
154 q
= poly_cache
.terms_
[j
];
163 Remove all numbers outside [0, 1] from SOL
166 filter_solutions (vector
<Real
> sol
)
168 for (vsize i
= sol
.size (); i
--;)
169 if (sol
[i
] < 0 || sol
[i
] > 1)
170 sol
.erase (sol
.begin () + i
);
175 find t such that derivative is proportional to DERIV
178 Bezier::solve_derivative (Offset deriv
) const
180 Polynomial xp
= polynomial (X_AXIS
);
181 Polynomial yp
= polynomial (Y_AXIS
);
185 Polynomial combine
= xp
* deriv
[Y_AXIS
] - yp
* deriv
[X_AXIS
];
187 return filter_solutions (combine
.solve ());
191 Find t such that curve_point (t)[AX] == COORDINATE
194 Bezier::solve_point (Axis ax
, Real coordinate
) const
196 Polynomial
p (polynomial (ax
));
197 p
.coefs_
[0] -= coordinate
;
199 vector
<Real
> sol (p
.solve ());
200 return filter_solutions (sol
);
204 Compute the bounding box dimensions in direction of A.
207 Bezier::extent (Axis a
) const
209 int o
= (a
+ 1)%NO_AXES
;
213 vector
<Real
> sols (solve_derivative (d
));
214 sols
.push_back (1.0);
215 sols
.push_back (0.0);
216 for (vsize i
= sols
.size (); i
--;)
218 Offset
o (curve_point (sols
[i
]));
219 iv
.unite (Interval (o
[a
], o
[a
]));
225 Bezier::control_point_extent (Axis a
) const
228 for (int i
= CONTROL_COUNT
; i
--;)
229 ext
.add_point (control_
[i
][a
]);
239 Bezier::scale (Real x
, Real y
)
241 for (int i
= CONTROL_COUNT
; i
--;)
243 control_
[i
][X_AXIS
] = x
* control_
[i
][X_AXIS
];
244 control_
[i
][Y_AXIS
] = y
* control_
[i
][Y_AXIS
];
249 Bezier::rotate (Real phi
)
251 Offset
rot (complex_exp (Offset (0, phi
)));
252 for (int i
= 0; i
< CONTROL_COUNT
; i
++)
253 control_
[i
] = complex_multiply (rot
, control_
[i
]);
257 Bezier::translate (Offset o
)
259 for (int i
= 0; i
< CONTROL_COUNT
; i
++)
264 Bezier::assert_sanity () const
266 for (int i
= 0; i
< CONTROL_COUNT
; i
++)
267 assert (!isnan (control_
[i
].length ())
268 && !isinf (control_
[i
].length ()));
275 for (int i
= 0; i
< CONTROL_COUNT
; i
++)
276 b2
.control_
[CONTROL_COUNT
- i
- 1] = control_
[i
];
282 Subdivide a bezier at T into LEFT_PART and RIGHT_PART
283 using deCasteljau's algorithm.
286 Bezier::subdivide (Real t
, Bezier
*left_part
, Bezier
*right_part
) const
288 Offset p
[CONTROL_COUNT
][CONTROL_COUNT
];
290 for (int i
= 0; i
< CONTROL_COUNT
; i
++)
291 p
[i
][CONTROL_COUNT
- 1 ] = control_
[i
];
292 for (int j
= CONTROL_COUNT
- 2; j
>= 0 ; j
--)
293 for (int i
= 0; i
< CONTROL_COUNT
-1; i
++)
294 p
[i
][j
] = p
[i
][j
+1] + t
* (p
[i
+1][j
+1] - p
[i
][j
+1]);
295 for (int i
= 0; i
< CONTROL_COUNT
; i
++)
297 left_part
->control_
[i
]=p
[0][CONTROL_COUNT
- 1 - i
];
298 right_part
->control_
[i
]=p
[i
][i
];
303 Extract a portion of a bezier from T_MIN to T_MAX
307 Bezier::extract (Real t_min
, Real t_max
) const
309 if ((t_min
< 0) || (t_max
) > 1)
311 ("bezier extract arguments outside of limits: curve may have bad shape");
314 ("lower bezier extract value not less than upper value: curve may have bad shape");
315 Bezier bez1
, bez2
, bez3
, bez4
;
319 subdivide (t_min
, &bez1
, &bez2
);
324 bez2
.subdivide ((t_max
-t_min
)/(1-t_min
), &bez3
, &bez4
);