2 vaticana-ligature.cc -- implement Vaticana_ligature
4 source file of the GNU LilyPond music typesetter
6 (c) 2003--2005 Juergen Reuter <reuter@ipd.uka.de>
9 #include "vaticana-ligature.hh"
14 #include "font-interface.hh"
16 #include "staff-symbol-referencer.hh"
17 #include "note-head.hh"
18 #include "output-def.hh"
23 vaticana_brew_cauda (Grob *me,
29 bool on_staffline = Staff_symbol_referencer::on_staffline (me, pos);
30 int interspaces = Staff_symbol_referencer::line_count (me)-1;
31 bool above_staff = pos > interspaces;
35 me->programming_error ("flexa cauda: invalid delta_pitch; assuming -1");
41 if (delta_pitch >= -1)
43 else if (delta_pitch >= -2)
50 if (delta_pitch >= -1)
55 else if (delta_pitch >= -2)
57 else if (delta_pitch >= -3)
62 Box cauda_box (Interval (0, thickness), Interval (-length, 0));
63 return Lookup::round_filled_box (cauda_box, blotdiameter);
67 * TODO: move this function to class Lookup?
70 vaticana_brew_flexa (Grob *me,
74 Real staff_space = Staff_symbol_referencer::staff_space (me);
76 Real right_height = 0.6 * staff_space;
79 SCM flexa_height_scm = me->get_property ("flexa-height");
80 if (flexa_height_scm != SCM_EOL)
82 interval = scm_to_int (flexa_height_scm);
86 me->warning ("Vaticana_ligature: "
87 "flexa-height undefined; assuming 0");
93 me->warning (_ ("ascending vaticana style flexa"));
96 Real width = robust_scm2double ( me->get_property ("flexa-width"), 2);
99 * Compensate curve thickness that appears to be smaller in steep
104 min (0.12 * abs (interval), 0.3) * staff_space;
107 * Compensate optical illusion regarding vertical position of left
108 * and right endings due to curved shape.
110 Real ypos_correction = -0.1*staff_space * sign (interval);
111 Real interval_correction = 0.2*staff_space * sign (interval);
112 Real corrected_interval = interval*staff_space + interval_correction;
115 * middle curve of flexa shape
118 curve.control_[0] = Offset (0.00 * width, 0.0);
119 curve.control_[1] = Offset (0.33 * width, corrected_interval / 2.0);
120 curve.control_[2] = Offset (0.66 * width, corrected_interval / 2.0);
121 curve.control_[3] = Offset (1.00 * width, corrected_interval / 2.0);
123 Bezier top_curve = curve, bottom_curve = curve;
124 for (int i = 0; i < 4; i++)
126 Real curve_thickness = 0.33 * ((3 - i)*left_height + i*right_height);
127 top_curve.control_[i] += Offset (0, 0.5 * curve_thickness);
128 bottom_curve.control_[i] -= Offset (0, 0.5 * curve_thickness);
134 Lookup::bezier_sandwich (top_curve, bottom_curve);
135 stencil.add_stencil (solid_head);
139 Bezier inner_top_curve = top_curve;
140 inner_top_curve.translate (Offset (0.0, -line_thickness));
142 Lookup::bezier_sandwich (top_curve, inner_top_curve);
143 stencil.add_stencil (top_edge);
145 Bezier inner_bottom_curve = bottom_curve;
146 inner_bottom_curve.translate (Offset (0.0, +line_thickness));
147 Stencil bottom_edge =
148 Lookup::bezier_sandwich (bottom_curve, inner_bottom_curve);
149 stencil.add_stencil (bottom_edge);
152 * TODO: Use horizontal slope with proper slope value rather
153 * than filled box for left edge, since the filled box stands
154 * out from the flexa shape if the interval is big and the line
155 * thickness small. The difficulty here is to compute a proper
156 * slope value, as it should roughly be equal with the slope of
157 * the left end of the bezier curve.
159 Box left_edge_box (Interval (0, line_thickness),
160 Interval (-0.5*left_height, +0.5*left_height));
161 Stencil left_edge = Lookup::filled_box (left_edge_box);
162 stencil.add_stencil (left_edge);
164 Box right_edge_box (Interval (-line_thickness, 0),
165 Interval (-0.5*right_height, +0.5*right_height));
166 Stencil right_edge = Lookup::filled_box (right_edge_box);
167 right_edge.translate_axis (width, X_AXIS);
168 right_edge.translate_axis (corrected_interval / 2.0, Y_AXIS);
169 stencil.add_stencil (right_edge);
171 stencil.translate_axis (ypos_correction, Y_AXIS);
176 vaticana_brew_join (Grob *me, int delta_pitch,
177 Real join_thickness, Real blotdiameter)
179 Real staff_space = Staff_symbol_referencer::staff_space (me);
182 me->programming_error (_f ("Vaticana_ligature: "
183 "zero join (delta_pitch == 0)"));
186 Interval x_extent = Interval (0, join_thickness);
187 Interval y_extent = (delta_pitch > 0) ?
188 Interval (0, delta_pitch * 0.5 * staff_space) : // ascending join
189 Interval (delta_pitch * 0.5 * staff_space, 0); // descending join
190 Box join_box (x_extent, y_extent);
191 return Lookup::round_filled_box (join_box, blotdiameter);
195 vaticana_brew_primitive (Grob *me)
197 SCM glyph_name_scm = me->get_property ("glyph-name");
198 if (glyph_name_scm == SCM_EOL)
200 me->programming_error ("Vaticana_ligature: "
201 "undefined glyph-name -> ignoring grob");
205 String glyph_name = ly_scm2string (glyph_name_scm);
208 Real thickness = robust_scm2double ( me->get_property ("thickness"), 1);
210 Real line_thickness =
211 thickness * me->get_layout ()->get_dimension (ly_symbol2scm ("linethickness"));
214 (me->get_layout ()->get_dimension (ly_symbol2scm ("blotdiameter")));
216 int pos = Staff_symbol_referencer::get_rounded_position (me);
218 SCM delta_pitch_scm = me->get_property ("delta-pitch");
220 if (delta_pitch_scm != SCM_EOL)
221 delta_pitch = scm_to_int (delta_pitch_scm);
225 Real x_offset = robust_scm2double ( me->get_property ("x-offset"), 0);
227 bool add_stem = to_boolean (me->get_property ("add-stem"));
228 bool add_cauda = to_boolean (me->get_property ("add-cauda"));
229 bool add_join = to_boolean (me->get_property ("add-join"));
231 if (!String::compare (glyph_name, ""))
234 * This is an empty head. This typically applies for the right
235 * side of a curved flexa shape, which is already typeset by the
236 * associated left side head. The only possible thing left to
237 * do is to draw a vertical join to the next head. (Urgh: need
240 Real staff_space = Staff_symbol_referencer::staff_space (me);
241 Real flexa_width = robust_scm2double ( me->get_property ("flexa-width"), 2) *staff_space;
243 Lookup::blank (Box (Interval (0, 0.5*flexa_width), Interval (0,0)));
245 else if (!String::compare (glyph_name, "flexa"))
247 out = vaticana_brew_flexa (me, true, line_thickness);
252 Font_interface::get_default_font (me)->
253 find_by_name ("noteheads." + glyph_name);
255 out.translate_axis (x_offset, X_AXIS);
256 Real head_width = out.extent (X_AXIS).length ();
261 vaticana_brew_cauda (me, pos, delta_pitch,
262 line_thickness, blotdiameter);
263 out.add_stencil (cauda);
269 vaticana_brew_cauda (me, pos, -1,
270 line_thickness, blotdiameter);
271 stem.translate_axis (head_width - line_thickness, X_AXIS);
272 out.add_stencil (stem);
278 vaticana_brew_join (me, delta_pitch, line_thickness, blotdiameter);
279 join.translate_axis (head_width - line_thickness, X_AXIS);
280 out.add_stencil (join);
286 MAKE_SCHEME_CALLBACK (Vaticana_ligature, brew_ligature_primitive, 1);
288 Vaticana_ligature::brew_ligature_primitive (SCM smob)
290 Grob *me = unsmob_grob (smob);
291 SCM primitive = vaticana_brew_primitive (me).smobbed_copy ();
295 MAKE_SCHEME_CALLBACK (Vaticana_ligature, print, 1);
297 Vaticana_ligature::print (SCM)
302 ADD_INTERFACE (Vaticana_ligature, "vaticana-ligature-interface",
303 "A vaticana style gregorian ligature",
304 "glyph-name flexa-height flexa-width thickness add-cauda "
305 "add-stem add-join delta-pitch x-offset "
306 "ligature-primitive-callback");