2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 2003--2011 Juergen Reuter <reuter@ipd.uka.de>
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/>.
20 #include "vaticana-ligature.hh"
23 #include "font-interface.hh"
24 #include "international.hh"
27 #include "note-head.hh"
28 #include "output-def.hh"
29 #include "staff-symbol-referencer.hh"
33 vaticana_brew_cauda (Grob
*me
,
39 bool on_staffline
= Staff_symbol_referencer::on_line (me
, pos
);
40 int interspaces
= Staff_symbol_referencer::line_count (me
) - 1;
41 bool above_staff
= pos
> interspaces
;
45 me
->programming_error ("flexa cauda: invalid delta_pitch; assuming -1");
51 if (delta_pitch
>= -1)
53 else if (delta_pitch
>= -2)
60 if (delta_pitch
>= -1)
65 else if (delta_pitch
>= -2)
67 else if (delta_pitch
>= -3)
72 Box
cauda_box (Interval (0, thickness
), Interval (-length
, 0));
73 return Lookup::round_filled_box (cauda_box
, blotdiameter
);
77 * TODO: move this function to class Lookup?
80 vaticana_brew_flexa (Grob
*me
,
84 Real staff_space
= Staff_symbol_referencer::staff_space (me
);
86 Real right_height
= 0.6 * staff_space
;
89 SCM flexa_height_scm
= me
->get_property ("flexa-height");
90 if (flexa_height_scm
!= SCM_EOL
)
91 interval
= scm_to_int (flexa_height_scm
);
94 me
->warning ("Vaticana_ligature: "
95 + _ ("flexa-height undefined; assuming 0"));
100 me
->warning (_ ("ascending vaticana style flexa"));
102 Real width
= robust_scm2double (me
->get_property ("flexa-width"), 2);
105 * Compensate curve thickness that appears to be smaller in steep
110 + min (0.12 * abs (interval
), 0.3) * staff_space
;
113 * Compensate optical illusion regarding vertical position of left
114 * and right endings due to curved shape.
116 Real ypos_correction
= -0.1 * staff_space
* sign (interval
);
117 Real interval_correction
= 0.2 * staff_space
* sign (interval
);
118 Real corrected_interval
= interval
* staff_space
+ interval_correction
;
121 * middle curve of flexa shape
124 curve
.control_
[0] = Offset (0.00 * width
, 0.0);
125 curve
.control_
[1] = Offset (0.33 * width
, corrected_interval
/ 2.0);
126 curve
.control_
[2] = Offset (0.66 * width
, corrected_interval
/ 2.0);
127 curve
.control_
[3] = Offset (1.00 * width
, corrected_interval
/ 2.0);
129 Bezier top_curve
= curve
, bottom_curve
= curve
;
130 for (int i
= 0; i
< 4; i
++)
132 Real curve_thickness
= 0.33 * ((3 - i
) * left_height
+ i
* right_height
);
133 top_curve
.control_
[i
] += Offset (0, 0.5 * curve_thickness
);
134 bottom_curve
.control_
[i
] -= Offset (0, 0.5 * curve_thickness
);
140 = Lookup::bezier_sandwich (top_curve
, bottom_curve
, 0.0);
141 stencil
.add_stencil (solid_head
);
145 Bezier inner_top_curve
= top_curve
;
146 inner_top_curve
.translate (Offset (0.0, -line_thickness
));
148 = Lookup::bezier_sandwich (top_curve
, inner_top_curve
, 0.0);
149 stencil
.add_stencil (top_edge
);
151 Bezier inner_bottom_curve
= bottom_curve
;
152 inner_bottom_curve
.translate (Offset (0.0, +line_thickness
));
154 = Lookup::bezier_sandwich (bottom_curve
, inner_bottom_curve
, 0.0);
155 stencil
.add_stencil (bottom_edge
);
158 * TODO: Use horizontal slope with proper slope value rather
159 * than filled box for left edge, since the filled box stands
160 * out from the flexa shape if the interval is big and the line
161 * thickness small. The difficulty here is to compute a proper
162 * slope value, as it should roughly be equal with the slope of
163 * the left end of the bezier curve.
165 Box
left_edge_box (Interval (0, line_thickness
),
166 Interval (-0.5 * left_height
, +0.5 * left_height
));
167 Stencil left_edge
= Lookup::filled_box (left_edge_box
);
168 stencil
.add_stencil (left_edge
);
170 Box
right_edge_box (Interval (-line_thickness
, 0),
171 Interval (-0.5 * right_height
, +0.5 * right_height
));
172 Stencil right_edge
= Lookup::filled_box (right_edge_box
);
173 right_edge
.translate_axis (width
, X_AXIS
);
174 right_edge
.translate_axis (corrected_interval
/ 2.0, Y_AXIS
);
175 stencil
.add_stencil (right_edge
);
177 stencil
.translate_axis (ypos_correction
, Y_AXIS
);
182 vaticana_brew_join (Grob
*me
, int delta_pitch
,
183 Real join_thickness
, Real blotdiameter
)
185 Real staff_space
= Staff_symbol_referencer::staff_space (me
);
188 me
->programming_error (_ ("Vaticana_ligature: "
189 "zero join (delta_pitch == 0)"));
190 return Lookup::blank (Box (Interval (0, 0), Interval (0, 0)));
192 Interval x_extent
= Interval (0, join_thickness
);
193 Interval y_extent
= (delta_pitch
> 0)
194 ? Interval (0, delta_pitch
* 0.5 * staff_space
) : // ascending join
195 Interval (delta_pitch
* 0.5 * staff_space
, 0); // descending join
196 Box
join_box (x_extent
, y_extent
);
197 return Lookup::round_filled_box (join_box
, blotdiameter
);
201 vaticana_brew_primitive (Grob
*me
)
203 SCM glyph_name_scm
= me
->get_property ("glyph-name");
204 if (glyph_name_scm
== SCM_EOL
)
206 me
->programming_error ("Vaticana_ligature: "
207 "undefined glyph-name -> ignoring grob");
208 return Lookup::blank (Box (Interval (0, 0), Interval (0, 0)));
211 string glyph_name
= ly_scm2string (glyph_name_scm
);
214 Real thickness
= robust_scm2double (me
->get_property ("thickness"), 1);
217 = thickness
* me
->layout ()->get_dimension (ly_symbol2scm ("line-thickness"));
220 = (me
->layout ()->get_dimension (ly_symbol2scm ("blot-diameter")));
222 int pos
= Staff_symbol_referencer::get_rounded_position (me
);
224 SCM delta_pitch_scm
= me
->get_property ("delta-position");
226 if (delta_pitch_scm
!= SCM_EOL
)
227 delta_pitch
= scm_to_int (delta_pitch_scm
);
231 Real x_offset
= robust_scm2double (me
->get_property ("x-offset"), 0);
233 bool add_stem
= to_boolean (me
->get_property ("add-stem"));
234 bool add_cauda
= to_boolean (me
->get_property ("add-cauda"));
235 bool add_join
= to_boolean (me
->get_property ("add-join"));
237 if (glyph_name
== "")
240 * This is an empty head. This typically applies for the right
241 * side of a curved flexa shape, which is already typeset by the
242 * associated left side head. The only possible thing left to
243 * do is to draw a vertical join to the next head. (Urgh: need
246 Real staff_space
= Staff_symbol_referencer::staff_space (me
);
247 Real flexa_width
= robust_scm2double (me
->get_property ("flexa-width"), 2) * staff_space
;
249 = Lookup::blank (Box (Interval (0, 0.5 * flexa_width
), Interval (0, 0)));
251 else if (glyph_name
== "flexa")
252 out
= vaticana_brew_flexa (me
, true, line_thickness
);
256 = Font_interface::get_default_font (me
)->
257 find_by_name ("noteheads.s" + glyph_name
);
259 out
.translate_axis (x_offset
, X_AXIS
);
260 Real head_width
= out
.extent (X_AXIS
).length ();
265 = vaticana_brew_cauda (me
, pos
, delta_pitch
,
266 line_thickness
, blotdiameter
);
267 out
.add_stencil (cauda
);
273 = vaticana_brew_cauda (me
, pos
, -1,
274 line_thickness
, blotdiameter
);
275 stem
.translate_axis (head_width
- line_thickness
, X_AXIS
);
276 out
.add_stencil (stem
);
282 = vaticana_brew_join (me
, delta_pitch
, line_thickness
, blotdiameter
);
283 join
.translate_axis (head_width
- line_thickness
, X_AXIS
);
284 out
.add_stencil (join
);
290 MAKE_SCHEME_CALLBACK (Vaticana_ligature
, brew_ligature_primitive
, 1);
292 Vaticana_ligature::brew_ligature_primitive (SCM smob
)
294 Grob
*me
= unsmob_grob (smob
);
295 SCM primitive
= vaticana_brew_primitive (me
).smobbed_copy ();
299 MAKE_SCHEME_CALLBACK (Vaticana_ligature
, print
, 1);
301 Vaticana_ligature::print (SCM
)
306 ADD_INTERFACE (Vaticana_ligature
,
307 "A vaticana style Gregorian ligature.",