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