(finish_primitive): compile fixes.
[lilypond.git] / lily / vaticana-ligature.cc
blob916c20e3d890a106118fd256f5b111ac9e57fe78
1 /*
2 vaticana-ligature.cc -- implement Vaticana_ligature
4 source file of the GNU LilyPond music typesetter
6 (c) 2003 Juergen Reuter <reuter@ipd.uka.de>
7 */
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"
22 * TODO: move this function to class Lookup?
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)
33 if (interval >= 0.0)
35 me->warning (_ ("ascending vaticana style flexa"));
38 Real space = Staff_symbol_referencer::staff_space (me);
39 Molecule molecule = Molecule ();
40 Real right_height = 0.6 * space;
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;
46 if (add_stem)
48 bool consider_interval =
49 stem_direction * interval > 0.0;
51 Interval stem_box_x (0, thickness);
52 Interval stem_box_y;
54 if (consider_interval)
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);
61 else
62 stem_box_y = Interval (0, space);
64 Real y_correction =
65 (stem_direction == UP) ?
66 +0.5*left_height :
67 -0.5*left_height - stem_box_y.length();
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);
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;
81 // middle curve of flexa
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);
88 Bezier top_curve = curve, bottom_curve = curve;
89 for (int i = 0; i < 4; i++)
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);
96 if (solid)
98 Molecule solid_head =
99 Lookup::bezier_sandwich (top_curve, bottom_curve);
100 molecule.add_molecule (solid_head);
102 else // outline
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);
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);
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);
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);
134 molecule.translate_axis (ypos_correction, Y_AXIS);
135 return molecule;
138 void
139 vaticana_add_ledger_lines (Grob *me, Molecule *out, int pos, Real offs,
140 bool ledger_take_space)
142 int interspaces = Staff_symbol_referencer::line_count (me)-1;
143 if (abs (pos) - interspaces > 1)
145 Interval hd = out->extent (X_AXIS);
146 Real left_ledger_protusion = hd.length ()/4;
147 Real right_ledger_protusion = left_ledger_protusion;
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);
160 Molecule
161 vaticana_brew_primitive (Grob *me, bool ledger_take_space)
163 SCM glyph_name_scm = me->get_grob_property ("glyph-name");
164 if (glyph_name_scm == SCM_EOL)
166 programming_error ("Vaticana_ligature:"
167 "undefined glyph-name -> ignoring grob");
168 return Molecule ();
171 String glyph_name = ly_scm2string (glyph_name_scm);
172 if (!String::compare (glyph_name, ""))
174 // empty head (typically, this is the right side of porrectus
175 // shape, which is already typeset by the associated left side
176 // head); nothing left to do
177 return Molecule ();
180 Molecule out;
181 int porrectus_height = 0;
182 Real thickness = 0.0;
183 Real porrectus_width = 0.0;
184 Real staff_space = Staff_symbol_referencer::staff_space (me);
186 SCM thickness_scm = me->get_grob_property ("thickness");
187 if (thickness_scm != SCM_EOL)
189 thickness = gh_scm2double (thickness_scm);
191 else
193 programming_error (_f ("Vaticana_ligature:"
194 "thickness undefined; assuming 1.4",
195 me));
196 thickness = 1.4 * me->get_paper ()->get_var ("linethickness");
199 Real x_offset = 0.0;
200 SCM x_offset_scm = me->get_grob_property ("x-offset");
201 if (x_offset_scm != SCM_EOL)
203 x_offset = gh_scm2double (x_offset_scm);
205 else
207 programming_error (_f ("Vaticana_ligature:"
208 "x-offset undefined; assuming 0.0",
209 me));
212 if (!String::compare (glyph_name, "porrectus"))
214 SCM porrectus_height_scm = me->get_grob_property ("porrectus-height");
215 if (porrectus_height_scm != SCM_EOL)
217 porrectus_height = gh_scm2int (porrectus_height_scm);
219 else
221 me->warning ("Vaticana_ligature: "
222 "porrectus-height undefined; assuming 0");
225 SCM porrectus_width_scm = me->get_grob_property ("porrectus-width");
226 if (porrectus_width_scm != SCM_EOL)
228 porrectus_width = gh_scm2double (porrectus_width_scm);
230 else
232 me->warning ("Vaticana_ligature:"
233 "porrectus-width undefined; assuming 2.0");
234 porrectus_width = 2.0 * staff_space;
237 bool add_stem = to_boolean (me->get_grob_property ("add-stem"));
238 out = vaticana_brew_flexa (me, porrectus_height, true,
239 porrectus_width, thickness, add_stem, DOWN);
241 else
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);
250 SCM join_left_scm = me->get_grob_property ("join-left");
251 if (join_left_scm != SCM_EOL)
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);
264 Molecule stem = Lookup::roundfilledbox (stem_box, blotdiameter);
265 out.add_molecule (stem);
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, "porrectus"))
272 pos += porrectus_height;
273 vaticana_add_ledger_lines(me, &out, pos, 0.5*porrectus_height, ledger_take_space);
276 return out;
279 MAKE_SCHEME_CALLBACK (Vaticana_ligature, brew_ligature_primitive, 1);
281 Vaticana_ligature::brew_ligature_primitive (SCM smob)
283 Grob *me = unsmob_grob (smob);
284 SCM primitive = vaticana_brew_primitive (me, false).smobbed_copy ();
285 return primitive;
288 MAKE_SCHEME_CALLBACK (Vaticana_ligature, brew_molecule, 1);
290 Vaticana_ligature::brew_molecule (SCM)
292 return SCM_EOL;
295 ADD_INTERFACE (Vaticana_ligature, "vaticana-ligature-interface",
296 "A vaticana style gregorian ligature",
297 "glyph-name porrectus-height porrectus-width thickness join-left "
298 "add-stem x-offset ligature-primitive-callback");