]> git.donarmstrong.com Git - lilypond.git/blob - lily/mensural-ligature.cc
*** empty log message ***
[lilypond.git] / lily / mensural-ligature.cc
1 /*
2   mensural-ligature.cc -- implement Mensural_ligature
3   
4   source file of the GNU LilyPond music typesetter
5   
6   (c) 2002--2005 Juergen Reuter <reuter@ipd.uka.de>
7 */
8
9 #include "mensural-ligature.hh"
10
11 #include <math.h>
12
13 #include "item.hh"
14 #include "font-interface.hh"
15 #include "lookup.hh"
16 #include "staff-symbol-referencer.hh"
17 #include "note-head.hh"
18 #include "output-def.hh"
19 #include "warn.hh"
20
21 /*
22  * TODO: divide this function into mensural and neo-mensural style.
23  *
24  * TODO: move this function to class Lookup?
25  */
26 Stencil
27 brew_flexa (Grob *me,
28             Real interval,
29             bool solid,
30             Real width,
31             Real thickness,
32             bool add_cauda,
33             Direction cauda_direction)
34 {
35   Real staff_space = Staff_symbol_referencer::staff_space (me);
36   Real height = 0.6 * staff_space;
37   Stencil stencil;
38
39   if (add_cauda)
40     {
41       bool consider_interval =
42         cauda_direction * interval > 0.0;
43
44       Interval cauda_box_x (0, thickness);
45       Interval cauda_box_y;
46
47       if (consider_interval)
48         {
49           Real y_length = max (interval/2.0*staff_space, 1.2*staff_space);
50           cauda_box_y = Interval (0, y_length);
51         }
52       else
53         cauda_box_y = Interval (0, staff_space);
54
55       Real y_correction =
56         (cauda_direction == UP) ?
57         +0.5*height :
58         -0.5*height - cauda_box_y.length ();
59
60       Box cauda_box (cauda_box_x, cauda_box_y);
61       Stencil cauda = Lookup::filled_box (cauda_box);
62       cauda.translate_axis (y_correction, Y_AXIS);
63       stencil.add_stencil (cauda);
64     }
65
66   Real slope = (interval / 2.0 * staff_space) / width;
67
68   // Compensate optical illusion regarding vertical position of left
69   // and right endings due to slope.
70   Real ypos_correction = -0.1*staff_space * sign (slope);
71   Real slope_correction = 0.2*staff_space * sign (slope);
72   Real corrected_slope = slope + slope_correction/width;
73
74   if (solid)
75     {
76       Stencil solid_head =
77         Lookup::beam (corrected_slope, width, height, 0.0);
78       stencil.add_stencil (solid_head);
79     }
80   else // outline
81     {
82       Stencil left_edge =
83         Lookup::beam (corrected_slope, thickness, height, 0.0);
84       stencil.add_stencil (left_edge);
85
86       Stencil right_edge =
87         Lookup::beam (corrected_slope, thickness, height, 0.0);
88       right_edge.translate_axis (width-thickness, X_AXIS);
89       right_edge.translate_axis (corrected_slope * (width-thickness), Y_AXIS);
90       stencil.add_stencil (right_edge);
91
92       Stencil bottom_edge =
93         Lookup::beam (corrected_slope, width, thickness, 0.0);
94       bottom_edge.translate_axis (-0.5*height, Y_AXIS);
95       stencil.add_stencil (bottom_edge);
96
97       Stencil top_edge =
98         Lookup::beam (corrected_slope, width, thickness, 0.0);
99       top_edge.translate_axis (+0.5*height, Y_AXIS);
100       stencil.add_stencil (top_edge);
101     }
102   stencil.translate_axis (ypos_correction, Y_AXIS);
103   return stencil;
104 }
105
106 Stencil
107 internal_brew_primitive (Grob *me)
108 {
109   SCM primitive_scm = me->get_property ("primitive");
110   if (primitive_scm == SCM_EOL)
111     {
112       programming_error ("Mensural_ligature:"
113                          "undefined primitive -> ignoring grob");
114       return Stencil ();
115     }
116
117   Stencil out;
118   int primitive = scm_to_int (primitive_scm);
119   int delta_pitch = 0;
120   Real thickness = 0.0;
121   Real flexa_width = 0.0;
122   Real staff_space = Staff_symbol_referencer::staff_space (me);
123   if (primitive & MLP_ANY)
124     {
125       thickness = robust_scm2double ( me->get_property ("thickness"), .14);
126     }
127
128   if (primitive & MLP_FLEXA)
129     {
130       delta_pitch = robust_scm2int (me->get_property ("delta-pitch"),
131                                     0);
132
133       flexa_width = robust_scm2double (me->get_property ("flexa-width"), 2.0 * staff_space);
134     }
135
136   switch (primitive)
137     {
138       case MLP_NONE:
139         return Stencil ();
140       case MLP_BB:
141         out = brew_flexa (me, delta_pitch, false,
142                           flexa_width, thickness, true, DOWN);
143         break;
144       case MLP_sc: // mensural brevis head with right cauda
145         out = Font_interface::get_default_font (me)->find_by_name ("noteheads.-2mensural");
146         break;
147       case MLP_ss: // mensural brevis head
148         out = Font_interface::get_default_font (me)->find_by_name ("noteheads.-1mensural");
149         break;
150       case MLP_cs: // mensural brevis head with left cauda
151         out = Font_interface::get_default_font (me)->find_by_name ("noteheads.lmensural");
152         break;
153       case MLP_SS:
154         out = brew_flexa (me, delta_pitch, false,
155                           flexa_width, thickness, true, UP);
156         break;
157       case MLP_LB:
158         out = brew_flexa (me, delta_pitch, false,
159                           flexa_width, thickness, false, CENTER);
160         break;
161       default:
162         programming_error (_f ("Mensural_ligature:"
163                                "unexpected case fall-through"));
164         return Stencil ();
165     }
166
167   SCM join_left_scm = me->get_property ("join-left-amount");
168   if (join_left_scm != SCM_EOL)
169     {
170       int join_left = scm_to_int (join_left_scm);
171       if (!join_left)
172         programming_error (_f ("Mensural_ligature: (join_left == 0)"));
173       Real blotdiameter = (me->get_layout ()->get_dimension (ly_symbol2scm ("blotdiameter")));
174       Interval x_extent = Interval (0, thickness);
175       Interval y_extent = (join_left > 0) ?
176         Interval (-join_left * 0.5 * staff_space, 0) :
177         Interval (0, -join_left * 0.5 * staff_space);
178       Box join_box (x_extent, y_extent);
179
180       Stencil join = Lookup::round_filled_box (join_box, blotdiameter);
181       out.add_stencil (join);
182     }
183
184   int pos = Staff_symbol_referencer::get_rounded_position (me);
185   if (primitive & MLP_FLEXA)
186     {
187       pos += delta_pitch;
188     }
189
190   return out;
191 }
192
193 MAKE_SCHEME_CALLBACK (Mensural_ligature, brew_ligature_primitive, 1);
194 SCM
195 Mensural_ligature::brew_ligature_primitive (SCM smob)
196 {
197   Grob *me = unsmob_grob (smob);
198   return internal_brew_primitive (me).smobbed_copy ();
199 }
200
201 MAKE_SCHEME_CALLBACK (Mensural_ligature, print, 1);
202 SCM
203 Mensural_ligature::print (SCM)
204 {
205   return SCM_EOL;
206 }
207
208 ADD_INTERFACE (Mensural_ligature, "mensural-ligature-interface",
209                "A mensural ligature",
210                "delta-pitch flexa-width head-width join-left join-left-amount "
211                "ligature-primitive-callback primitive thickness");