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