]> git.donarmstrong.com Git - lilypond.git/blob - lily/vaticana-ligature.cc
* lily/tie-column.cc (set_manual_tie_configuration): new function.
[lilypond.git] / lily / vaticana-ligature.cc
1 /*
2   vaticana-ligature.cc -- implement Vaticana_ligature
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 2003--2005 Juergen Reuter <reuter@ipd.uka.de>
7 */
8
9 #include "vaticana-ligature.hh"
10
11 #include <cmath>
12 using namespace std;
13
14 #include "item.hh"
15 #include "font-interface.hh"
16 #include "lookup.hh"
17 #include "staff-symbol-referencer.hh"
18 #include "note-head.hh"
19 #include "output-def.hh"
20 #include "bezier.hh"
21 #include "warn.hh"
22
23 Stencil
24 vaticana_brew_cauda (Grob *me,
25                      int pos,
26                      int delta_pitch,
27                      Real thickness,
28                      Real blotdiameter)
29 {
30   bool on_staffline = Staff_symbol_referencer::on_staffline (me, pos);
31   int interspaces = Staff_symbol_referencer::line_count (me) - 1;
32   bool above_staff = pos > interspaces;
33
34   if (delta_pitch > -1)
35     {
36       me->programming_error ("flexa cauda: invalid delta_pitch; assuming -1");
37       delta_pitch = -1;
38     }
39   Real length;
40   if (on_staffline)
41     {
42       if (delta_pitch >= -1)
43         length = 1.30;
44       else if (delta_pitch >= -2)
45         length = 1.35;
46       else
47         length = 1.85;
48     }
49   else
50     {
51       if (delta_pitch >= -1)
52         if (above_staff)
53           length = 1.30;
54         else
55           length = 1.00;
56       else if (delta_pitch >= -2)
57         length = 1.35;
58       else if (delta_pitch >= -3)
59         length = 1.50;
60       else
61         length = 1.85;
62     }
63   Box cauda_box (Interval (0, thickness), Interval (-length, 0));
64   return Lookup::round_filled_box (cauda_box, blotdiameter);
65 }
66
67 /*
68  * TODO: move this function to class Lookup?
69  */
70 Stencil
71 vaticana_brew_flexa (Grob *me,
72                      bool solid,
73                      Real line_thickness)
74 {
75   Real staff_space = Staff_symbol_referencer::staff_space (me);
76   Stencil stencil;
77   Real right_height = 0.6 * staff_space;
78
79   Real interval;
80   SCM flexa_height_scm = me->get_property ("flexa-height");
81   if (flexa_height_scm != SCM_EOL)
82     interval = scm_to_int (flexa_height_scm);
83   else
84     {
85       me->warning ("Vaticana_ligature: "
86                    + _ ("flexa-height undefined; assuming 0"));
87       interval = 0.0;
88     }
89
90   if (interval >= 0.0)
91     me->warning (_ ("ascending vaticana style flexa"));
92
93   Real width = robust_scm2double (me->get_property ("flexa-width"), 2);
94
95   /*
96    * Compensate curve thickness that appears to be smaller in steep
97    * section of bend.
98    */
99   Real left_height
100     = right_height
101     + min (0.12 * abs (interval), 0.3) * staff_space;
102
103   /*
104    * Compensate optical illusion regarding vertical position of left
105    * and right endings due to curved shape.
106    */
107   Real ypos_correction = -0.1 * staff_space * sign (interval);
108   Real interval_correction = 0.2 * staff_space * sign (interval);
109   Real corrected_interval = interval * staff_space + interval_correction;
110
111   /*
112    * middle curve of flexa shape
113    */
114   Bezier curve;
115   curve.control_[0] = Offset (0.00 * width, 0.0);
116   curve.control_[1] = Offset (0.33 * width, corrected_interval / 2.0);
117   curve.control_[2] = Offset (0.66 * width, corrected_interval / 2.0);
118   curve.control_[3] = Offset (1.00 * width, corrected_interval / 2.0);
119
120   Bezier top_curve = curve, bottom_curve = curve;
121   for (int i = 0; i < 4; i++)
122     {
123       Real curve_thickness = 0.33 * ((3 - i) * left_height + i * right_height);
124       top_curve.control_[i] += Offset (0, 0.5 * curve_thickness);
125       bottom_curve.control_[i] -= Offset (0, 0.5 * curve_thickness);
126     }
127
128   if (solid)
129     {
130       Stencil solid_head
131         = Lookup::bezier_sandwich (top_curve, bottom_curve);
132       stencil.add_stencil (solid_head);
133     }
134   else // outline
135     {
136       Bezier inner_top_curve = top_curve;
137       inner_top_curve.translate (Offset (0.0, -line_thickness));
138       Stencil top_edge
139         = Lookup::bezier_sandwich (top_curve, inner_top_curve);
140       stencil.add_stencil (top_edge);
141
142       Bezier inner_bottom_curve = bottom_curve;
143       inner_bottom_curve.translate (Offset (0.0, +line_thickness));
144       Stencil bottom_edge
145         = Lookup::bezier_sandwich (bottom_curve, inner_bottom_curve);
146       stencil.add_stencil (bottom_edge);
147
148       /*
149        * TODO: Use horizontal slope with proper slope value rather
150        * than filled box for left edge, since the filled box stands
151        * out from the flexa shape if the interval is big and the line
152        * thickness small.  The difficulty here is to compute a proper
153        * slope value, as it should roughly be equal with the slope of
154        * the left end of the bezier curve.
155        */
156       Box left_edge_box (Interval (0, line_thickness),
157                          Interval (-0.5 * left_height, +0.5 * left_height));
158       Stencil left_edge = Lookup::filled_box (left_edge_box);
159       stencil.add_stencil (left_edge);
160
161       Box right_edge_box (Interval (-line_thickness, 0),
162                           Interval (-0.5 * right_height, +0.5 * right_height));
163       Stencil right_edge = Lookup::filled_box (right_edge_box);
164       right_edge.translate_axis (width, X_AXIS);
165       right_edge.translate_axis (corrected_interval / 2.0, Y_AXIS);
166       stencil.add_stencil (right_edge);
167     }
168   stencil.translate_axis (ypos_correction, Y_AXIS);
169   return stencil;
170 }
171
172 Stencil
173 vaticana_brew_join (Grob *me, int delta_pitch,
174                     Real join_thickness, Real blotdiameter)
175 {
176   Real staff_space = Staff_symbol_referencer::staff_space (me);
177   if (!delta_pitch)
178     {
179       me->programming_error (_f ("Vaticana_ligature: "
180                                  "zero join (delta_pitch == 0)"));
181       return Stencil ();
182     }
183   Interval x_extent = Interval (0, join_thickness);
184   Interval y_extent = (delta_pitch > 0)
185     ? Interval (0, delta_pitch * 0.5 * staff_space) : // ascending join
186     Interval (delta_pitch * 0.5 * staff_space, 0); // descending join
187   Box join_box (x_extent, y_extent);
188   return Lookup::round_filled_box (join_box, blotdiameter);
189 }
190
191 Stencil
192 vaticana_brew_primitive (Grob *me)
193 {
194   SCM glyph_name_scm = me->get_property ("glyph-name");
195   if (glyph_name_scm == SCM_EOL)
196     {
197       me->programming_error ("Vaticana_ligature: "
198                              "undefined glyph-name -> ignoring grob");
199       return Stencil ();
200     }
201
202   String glyph_name = ly_scm2string (glyph_name_scm);
203
204   Stencil out;
205   Real thickness = robust_scm2double (me->get_property ("thickness"), 1);
206
207   Real line_thickness
208     = thickness * me->get_layout ()->get_dimension (ly_symbol2scm ("linethickness"));
209
210   Real blotdiameter
211     = (me->get_layout ()->get_dimension (ly_symbol2scm ("blotdiameter")));
212
213   int pos = Staff_symbol_referencer::get_rounded_position (me);
214
215   SCM delta_pitch_scm = me->get_property ("delta-pitch");
216   int delta_pitch;
217   if (delta_pitch_scm != SCM_EOL)
218     delta_pitch = scm_to_int (delta_pitch_scm);
219   else
220     delta_pitch = 0;
221
222   Real x_offset = robust_scm2double (me->get_property ("x-offset"), 0);
223
224   bool add_stem = to_boolean (me->get_property ("add-stem"));
225   bool add_cauda = to_boolean (me->get_property ("add-cauda"));
226   bool add_join = to_boolean (me->get_property ("add-join"));
227
228   if (!String::compare (glyph_name, ""))
229     {
230       /*
231        * This is an empty head.  This typically applies for the right
232        * side of a curved flexa shape, which is already typeset by the
233        * associated left side head.  The only possible thing left to
234        * do is to draw a vertical join to the next head.  (Urgh: need
235        * flexa_width.)
236        */
237       Real staff_space = Staff_symbol_referencer::staff_space (me);
238       Real flexa_width = robust_scm2double (me->get_property ("flexa-width"), 2) * staff_space;
239       out
240         = Lookup::blank (Box (Interval (0, 0.5 * flexa_width), Interval (0, 0)));
241     }
242   else if (!String::compare (glyph_name, "flexa"))
243     out = vaticana_brew_flexa (me, true, line_thickness);
244   else
245     {
246       out
247         = Font_interface::get_default_font (me)->
248         find_by_name ("noteheads." + glyph_name);
249     }
250   out.translate_axis (x_offset, X_AXIS);
251   Real head_width = out.extent (X_AXIS).length ();
252
253   if (add_cauda)
254     {
255       Stencil cauda
256         = vaticana_brew_cauda (me, pos, delta_pitch,
257                                line_thickness, blotdiameter);
258       out.add_stencil (cauda);
259     }
260
261   if (add_stem)
262     {
263       Stencil stem
264         = vaticana_brew_cauda (me, pos, -1,
265                                line_thickness, blotdiameter);
266       stem.translate_axis (head_width - line_thickness, X_AXIS);
267       out.add_stencil (stem);
268     }
269
270   if (add_join)
271     {
272       Stencil join
273         = vaticana_brew_join (me, delta_pitch, line_thickness, blotdiameter);
274       join.translate_axis (head_width - line_thickness, X_AXIS);
275       out.add_stencil (join);
276     }
277
278   return out;
279 }
280
281 MAKE_SCHEME_CALLBACK (Vaticana_ligature, brew_ligature_primitive, 1);
282 SCM
283 Vaticana_ligature::brew_ligature_primitive (SCM smob)
284 {
285   Grob *me = unsmob_grob (smob);
286   SCM primitive = vaticana_brew_primitive (me).smobbed_copy ();
287   return primitive;
288 }
289
290 MAKE_SCHEME_CALLBACK (Vaticana_ligature, print, 1);
291 SCM
292 Vaticana_ligature::print (SCM)
293 {
294   return SCM_EOL;
295 }
296
297 ADD_INTERFACE (Vaticana_ligature, "vaticana-ligature-interface",
298                "A vaticana style gregorian ligature",
299                "glyph-name flexa-height flexa-width thickness add-cauda "
300                "add-stem add-join delta-pitch x-offset "
301                "ligature-primitive-callback");