2 bezier.cc -- implement Bezier and Bezier_bow
4 source file of the GNU LilyPond music typesetter
6 (c) 1998--2009 Jan Nieuwenhuizen <janneke@gnu.org>
11 #include "libc-extension.hh"
13 Real binomial_coefficient_3
[] = {
18 scale (vector
<Offset
> *array
, Real x
, Real y
)
20 for (vsize i
= 0; i
< array
->size (); i
++)
22 (*array
)[i
][X_AXIS
] = x
* (*array
)[i
][X_AXIS
];
23 (*array
)[i
][Y_AXIS
] = y
* (*array
)[i
][Y_AXIS
];
28 rotate (vector
<Offset
> *array
, Real phi
)
30 Offset
rot (complex_exp (Offset (0, phi
)));
31 for (vsize i
= 0; i
< array
->size (); i
++)
32 (*array
)[i
] = complex_multiply (rot
, (*array
)[i
]);
36 translate (vector
<Offset
> *array
, Offset o
)
38 for (vsize i
= 0; i
< array
->size (); i
++)
43 Formula of the bezier 3-spline
45 sum_{j = 0}^3 (3 over j) z_j (1-t)^ (3-j) t^j
48 A is the axis of X coordinate.
52 Bezier::get_other_coordinate (Axis a
, Real x
) const
54 Axis other
= Axis ((a
+1) % NO_AXES
);
55 vector
<Real
> ts
= solve_point (a
, x
);
59 programming_error ("no solution found for Bezier intersection");
64 Offset c
= curve_point (ts
[0]);
65 if (fabs (c
[a
] - x
) > 1e-8)
66 programming_error ("bezier intersection not correct?");
69 return curve_coordinate (ts
[0], other
);
73 Bezier::curve_coordinate (Real t
, Axis a
) const
78 for (int i
= 1; i
< 4; i
++)
79 one_min_tj
[i
] = one_min_tj
[i
- 1] * (1 - t
);
82 for (int j
= 0; j
< 4; j
++)
84 r
+= control_
[j
][a
] * binomial_coefficient_3
[j
]
85 * tj
* one_min_tj
[3 - j
];
94 Bezier::curve_point (Real t
) const
99 for (int i
= 1; i
< 4; i
++)
100 one_min_tj
[i
] = one_min_tj
[i
- 1] * (1 - t
);
103 for (int j
= 0; j
< 4; j
++)
105 o
+= control_
[j
] * binomial_coefficient_3
[j
]
106 * tj
* one_min_tj
[3 - j
];
112 assert (fabs (o
[X_AXIS
] - polynomial (X_AXIS
).eval (t
)) < 1e-8);
113 assert (fabs (o
[Y_AXIS
] - polynomial (Y_AXIS
).eval (t
)) < 1e-8);
120 Cache binom (3, j) t^j (1-t)^{3-j}
122 struct Polynomial_cache
{
123 Polynomial terms_
[4];
126 for (int j
= 0; j
<= 3; j
++)
128 = binomial_coefficient_3
[j
]
129 * Polynomial::power (j
, Polynomial (0, 1))
130 * Polynomial::power (3 - j
, Polynomial (1, -1));
134 static Polynomial_cache poly_cache
;
137 Bezier::polynomial (Axis a
) const
141 for (int j
= 0; j
<= 3; j
++)
143 q
= poly_cache
.terms_
[j
];
152 Remove all numbers outside [0, 1] from SOL
155 filter_solutions (vector
<Real
> sol
)
157 for (vsize i
= sol
.size (); i
--;)
158 if (sol
[i
] < 0 || sol
[i
] > 1)
159 sol
.erase (sol
.begin () + i
);
164 find t such that derivative is proportional to DERIV
167 Bezier::solve_derivative (Offset deriv
) const
169 Polynomial xp
= polynomial (X_AXIS
);
170 Polynomial yp
= polynomial (Y_AXIS
);
174 Polynomial combine
= xp
* deriv
[Y_AXIS
] - yp
* deriv
[X_AXIS
];
176 return filter_solutions (combine
.solve ());
180 Find t such that curve_point (t)[AX] == COORDINATE
183 Bezier::solve_point (Axis ax
, Real coordinate
) const
185 Polynomial
p (polynomial (ax
));
186 p
.coefs_
[0] -= coordinate
;
188 vector
<Real
> sol (p
.solve ());
189 return filter_solutions (sol
);
193 Compute the bounding box dimensions in direction of A.
196 Bezier::extent (Axis a
) const
198 int o
= (a
+ 1)%NO_AXES
;
202 vector
<Real
> sols (solve_derivative (d
));
203 sols
.push_back (1.0);
204 sols
.push_back (0.0);
205 for (vsize i
= sols
.size (); i
--;)
207 Offset
o (curve_point (sols
[i
]));
208 iv
.unite (Interval (o
[a
], o
[a
]));
214 Bezier::control_point_extent (Axis a
) const
217 for (int i
= CONTROL_COUNT
; i
--;)
218 ext
.add_point (control_
[i
][a
]);
228 Bezier::scale (Real x
, Real y
)
230 for (int i
= CONTROL_COUNT
; i
--;)
232 control_
[i
][X_AXIS
] = x
* control_
[i
][X_AXIS
];
233 control_
[i
][Y_AXIS
] = y
* control_
[i
][Y_AXIS
];
238 Bezier::rotate (Real phi
)
240 Offset
rot (complex_exp (Offset (0, phi
)));
241 for (int i
= 0; i
< CONTROL_COUNT
; i
++)
242 control_
[i
] = complex_multiply (rot
, control_
[i
]);
246 Bezier::translate (Offset o
)
248 for (int i
= 0; i
< CONTROL_COUNT
; i
++)
253 Bezier::assert_sanity () const
255 for (int i
= 0; i
< CONTROL_COUNT
; i
++)
256 assert (!isnan (control_
[i
].length ())
257 && !isinf (control_
[i
].length ()));
264 for (int i
= 0; i
< CONTROL_COUNT
; i
++)
265 b2
.control_
[CONTROL_COUNT
- i
- 1] = control_
[i
];
271 Subdivide a bezier at T into LEFT_PART and RIGHT_PART
272 using deCasteljau's algorithm.
275 Bezier::subdivide (Real t
, Bezier
*left_part
, Bezier
*right_part
) const
277 Offset p
[CONTROL_COUNT
][CONTROL_COUNT
];
279 for (int i
= 0; i
< CONTROL_COUNT
; i
++)
280 p
[i
][CONTROL_COUNT
- 1 ] = control_
[i
];
281 for (int j
= CONTROL_COUNT
- 2; j
>= 0 ; j
--)
282 for (int i
= 0; i
< CONTROL_COUNT
-1; i
++)
283 p
[i
][j
] = p
[i
][j
+1] + t
* (p
[i
+1][j
+1] - p
[i
][j
+1]);
284 for (int i
= 0; i
< CONTROL_COUNT
; i
++)
286 left_part
->control_
[i
]=p
[0][CONTROL_COUNT
- 1 - i
];
287 right_part
->control_
[i
]=p
[i
][i
];
292 Extract a portion of a bezier from T_MIN to T_MAX
296 Bezier::extract (Real t_min
, Real t_max
) const
298 if ((t_min
< 0) || (t_max
) > 1)
300 ("bezier extract arguments outside of limits: curve may have bad shape");
303 ("lower bezier extract value not less than upper value: curve may have bad shape");
304 Bezier bez1
, bez2
, bez3
, bez4
;
308 subdivide (t_min
, &bez1
, &bez2
);
313 bez2
.subdivide ((t_max
-t_min
)/(1-t_min
), &bez3
, &bez4
);