2 vaticana-ligature.cc -- implement Vaticana_ligature
4 source file of the GNU LilyPond music typesetter
6 (c) 2003 Juergen Reuter <reuter@ipd.uka.de>
11 #include "vaticana-ligature.hh"
12 #include "font-interface.hh"
13 #include "molecule.hh"
15 #include "staff-symbol-referencer.hh"
16 #include "note-head.hh"
17 #include "paper-def.hh"
22 vaticana_brew_cauda (Grob
*me
,
28 bool on_staffline
= Staff_symbol_referencer::on_staffline (me
, pos
);
29 int interspaces
= Staff_symbol_referencer::line_count (me
)-1;
30 bool above_staff
= pos
> interspaces
;
34 me
->programming_error ("flexa cauda: invalid delta_pitch; assuming -1");
40 if (delta_pitch
>= -1)
42 else if (delta_pitch
>= -2)
49 if (delta_pitch
>= -1)
54 else if (delta_pitch
>= -2)
56 else if (delta_pitch
>= -3)
61 Box
cauda_box (Interval (0, thickness
), Interval (-length
, 0));
62 return Lookup::round_filled_box (cauda_box
, blotdiameter
);
66 * TODO: move this function to class Lookup?
69 vaticana_brew_flexa (Grob
*me
,
73 Real staff_space
= Staff_symbol_referencer::staff_space (me
);
74 Molecule molecule
= Molecule ();
75 Real right_height
= 0.6 * staff_space
;
78 SCM flexa_height_scm
= me
->get_grob_property ("flexa-height");
79 if (flexa_height_scm
!= SCM_EOL
)
81 interval
= gh_scm2int (flexa_height_scm
);
85 me
->warning ("Vaticana_ligature: "
86 "flexa-height undefined; assuming 0");
92 me
->warning (_ ("ascending vaticana style flexa"));
96 SCM flexa_width_scm
= me
->get_grob_property ("flexa-width");
97 if (flexa_width_scm
!= SCM_EOL
)
99 width
= gh_scm2double (flexa_width_scm
);
103 me
->warning ("Vaticana_ligature: "
104 "flexa-width undefined; assuming 2.0");
105 width
= 2.0 * staff_space
;
109 * Compensate curve thickness that appears to be smaller in steep
114 min (0.12 * abs(interval
), 0.3) * staff_space
;
117 * Compensate optical illusion regarding vertical position of left
118 * and right endings due to curved shape.
120 Real ypos_correction
= -0.1*staff_space
* sign(interval
);
121 Real interval_correction
= 0.2*staff_space
* sign(interval
);
122 Real corrected_interval
= interval
*staff_space
+ interval_correction
;
125 * middle curve of flexa shape
128 curve
.control_
[0] = Offset (0.00 * width
, 0.0);
129 curve
.control_
[1] = Offset (0.33 * width
, corrected_interval
/ 2.0);
130 curve
.control_
[2] = Offset (0.66 * width
, corrected_interval
/ 2.0);
131 curve
.control_
[3] = Offset (1.00 * width
, corrected_interval
/ 2.0);
133 Bezier top_curve
= curve
, bottom_curve
= curve
;
134 for (int i
= 0; i
< 4; i
++)
136 Real curve_thickness
= 0.33 * ((3 - i
)*left_height
+ i
*right_height
);
137 top_curve
.control_
[i
] += Offset (0, 0.5 * curve_thickness
);
138 bottom_curve
.control_
[i
] -= Offset (0, 0.5 * curve_thickness
);
143 Molecule solid_head
=
144 Lookup::bezier_sandwich (top_curve
, bottom_curve
);
145 molecule
.add_molecule (solid_head
);
149 Bezier inner_top_curve
= top_curve
;
150 inner_top_curve
.translate (Offset (0.0, -line_thickness
));
152 Lookup::bezier_sandwich (top_curve
, inner_top_curve
);
153 molecule
.add_molecule(top_edge
);
155 Bezier inner_bottom_curve
= bottom_curve
;
156 inner_bottom_curve
.translate (Offset (0.0, +line_thickness
));
157 Molecule bottom_edge
=
158 Lookup::bezier_sandwich (bottom_curve
, inner_bottom_curve
);
159 molecule
.add_molecule(bottom_edge
);
162 * TODO: Use horizontal slope with proper slope value rather
163 * than filled box for left edge, since the filled box stands
164 * out from the flexa shape if the interval is big and the line
165 * thickness small. The difficulty here is to compute a proper
166 * slope value, as it should roughly be equal with the slope of
167 * the left end of the bezier curve.
169 Box
left_edge_box (Interval (0, line_thickness
),
170 Interval (-0.5*left_height
, +0.5*left_height
));
171 Molecule left_edge
= Lookup::filledbox (left_edge_box
);
172 molecule
.add_molecule(left_edge
);
174 Box
right_edge_box (Interval (-line_thickness
, 0),
175 Interval (-0.5*right_height
, +0.5*right_height
));
176 Molecule right_edge
= Lookup::filledbox (right_edge_box
);
177 right_edge
.translate_axis (width
, X_AXIS
);
178 right_edge
.translate_axis (corrected_interval
/ 2.0, Y_AXIS
);
179 molecule
.add_molecule(right_edge
);
181 molecule
.translate_axis (ypos_correction
, Y_AXIS
);
186 vaticana_brew_join (Grob
*me
, int delta_pitch
,
187 Real join_thickness
, Real blotdiameter
)
189 Real staff_space
= Staff_symbol_referencer::staff_space (me
);
192 me
->programming_error (_f ("Vaticana_ligature: "
193 "zero join (delta_pitch == 0)"));
196 Interval x_extent
= Interval (0, join_thickness
);
197 Interval y_extent
= (delta_pitch
> 0) ?
198 Interval (0, delta_pitch
* 0.5 * staff_space
) : // ascending join
199 Interval (delta_pitch
* 0.5 * staff_space
, 0); // descending join
200 Box
join_box (x_extent
, y_extent
);
201 return Lookup::round_filled_box (join_box
, blotdiameter
);
205 vaticana_add_ledger_lines (Grob
*me
, Molecule
*out
, int pos
, Real offs
,
206 bool ledger_take_space
)
208 int interspaces
= Staff_symbol_referencer::line_count (me
)-1;
209 if (abs (pos
) - interspaces
> 1)
211 Interval hd
= out
->extent (X_AXIS
);
212 Real left_ledger_protusion
= hd
.length ()/4;
213 Real right_ledger_protusion
= left_ledger_protusion
;
215 Interval l_extents
= Interval (hd
[LEFT
] - left_ledger_protusion
,
216 hd
[RIGHT
] + right_ledger_protusion
);
217 Molecule ledger_lines
=
218 Note_head::brew_ledger_lines (me
, pos
, interspaces
,
221 ledger_lines
.translate_axis (offs
, Y_AXIS
);
222 out
->add_molecule (ledger_lines
);
227 vaticana_brew_primitive (Grob
*me
, bool ledger_take_space
)
229 SCM glyph_name_scm
= me
->get_grob_property ("glyph-name");
230 if (glyph_name_scm
== SCM_EOL
)
232 me
->programming_error ("Vaticana_ligature: "
233 "undefined glyph-name -> ignoring grob");
237 String glyph_name
= ly_scm2string (glyph_name_scm
);
240 int flexa_height
= 0;
243 SCM thickness_scm
= me
->get_grob_property ("thickness");
244 if (thickness_scm
!= SCM_EOL
)
246 thickness
= gh_scm2double (thickness_scm
);
250 me
->programming_error ("Vaticana_ligature: "
251 "thickness undefined; assuming 1.0");
255 Real line_thickness
=
256 thickness
* me
->get_paper ()->get_realvar (ly_symbol2scm ("linethickness"));
259 (me
->get_paper ()->get_realvar (ly_symbol2scm ("blotdiameter")));
261 int pos
= (int)rint (Staff_symbol_referencer::get_position (me
));
263 SCM delta_pitch_scm
= me
->get_grob_property ("delta-pitch");
265 if (delta_pitch_scm
!= SCM_EOL
)
266 delta_pitch
= gh_scm2int (delta_pitch_scm
);
271 SCM x_offset_scm
= me
->get_grob_property ("x-offset");
272 if (x_offset_scm
!= SCM_EOL
)
274 x_offset
= gh_scm2double (x_offset_scm
);
278 me
->programming_error ("Vaticana_ligature: "
279 "x-offset undefined; assuming 0.0");
282 bool add_stem
= to_boolean (me
->get_grob_property ("add-stem"));
283 bool add_cauda
= to_boolean (me
->get_grob_property ("add-cauda"));
284 bool add_join
= to_boolean (me
->get_grob_property ("add-join"));
286 if (!String::compare (glyph_name
, ""))
289 * This is an empty head. This typically applies for the right
290 * side of a curved flexa shape, which is already typeset by the
291 * associated left side head. The only possible thing left to
292 * do is to draw a vertical join to the next head. (Urgh: need
295 Real staff_space
= Staff_symbol_referencer::staff_space (me
);
297 SCM flexa_width_scm
= me
->get_grob_property ("flexa-width");
298 if (flexa_width_scm
!= SCM_EOL
)
300 flexa_width
= gh_scm2double (flexa_width_scm
);
304 me
->warning ("Vaticana_ligature: "
305 "flexa-width undefined; assuming 2.0");
306 flexa_width
= 2.0 * staff_space
;
309 Lookup::blank (Box (Interval (0, 0.5*flexa_width
), Interval (0,0)));
311 else if (!String::compare (glyph_name
, "flexa"))
313 out
= vaticana_brew_flexa (me
, true, line_thickness
);
318 Font_interface::get_default_font (me
)->
319 find_by_name ("noteheads-" + glyph_name
);
321 out
.translate_axis (x_offset
, X_AXIS
);
322 Real head_width
= out
.extent (X_AXIS
).length ();
327 vaticana_brew_cauda (me
, pos
, delta_pitch
,
328 line_thickness
, blotdiameter
);
329 out
.add_molecule (cauda
);
335 vaticana_brew_cauda (me
, pos
, -1,
336 line_thickness
, blotdiameter
);
337 stem
.translate_axis (head_width
- line_thickness
, X_AXIS
);
338 out
.add_molecule (stem
);
344 vaticana_brew_join (me
, delta_pitch
, line_thickness
, blotdiameter
);
345 join
.translate_axis (head_width
- line_thickness
, X_AXIS
);
346 out
.add_molecule (join
);
349 vaticana_add_ledger_lines(me
, &out
, pos
, 0, ledger_take_space
);
350 if (!String::compare (glyph_name
, "flexa"))
353 vaticana_add_ledger_lines(me
, &out
, pos
, 0.5*flexa_height
,
360 MAKE_SCHEME_CALLBACK (Vaticana_ligature
, brew_ligature_primitive
, 1);
362 Vaticana_ligature::brew_ligature_primitive (SCM smob
)
364 Grob
*me
= unsmob_grob (smob
);
365 SCM primitive
= vaticana_brew_primitive (me
, false).smobbed_copy ();
369 MAKE_SCHEME_CALLBACK (Vaticana_ligature
, brew_molecule
, 1);
371 Vaticana_ligature::brew_molecule (SCM
)
376 ADD_INTERFACE (Vaticana_ligature
, "vaticana-ligature-interface",
377 "A vaticana style gregorian ligature",
378 "glyph-name flexa-height flexa-width thickness add-cauda "
379 "add-stem add-join delta-pitch x-offset "
380 "ligature-primitive-callback");