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>
11 #include "vaticana-ligature.hh"
12 #include "font-interface.hh"
13 #include "molecule.hh"
15 #include "staff-symbol-referencer.hh"
16 #include "note-head.hh"
17 #include "paper-def.hh"
22 * TODO: move this function to class Lookup?
25 vaticana_brew_flexa (Grob
*me
,
31 Direction stem_direction
)
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
44 Real left_height
= right_height
+ min (0.12 * abs(interval
), 0.3) * space
;
48 bool consider_interval
=
49 stem_direction
* interval
> 0.0;
51 Interval
stem_box_x (0, thickness
);
54 if (consider_interval
)
56 Real y_length
= max (abs(interval
)/2.0*space
+
57 (right_height
-left_height
),
59 stem_box_y
= Interval (0, y_length
);
62 stem_box_y
= Interval (0, space
);
65 (stem_direction
== UP
) ?
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
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
);
99 Lookup::bezier_sandwich (top_curve
, bottom_curve
);
100 molecule
.add_molecule (solid_head
);
104 Bezier inner_top_curve
= top_curve
;
105 inner_top_curve
.translate (Offset (0.0, -thickness
));
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
);
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
,
155 ledger_lines
.translate_axis (offs
, Y_AXIS
);
156 out
->add_molecule (ledger_lines
);
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");
171 String glyph_name
= ly_symbol2string (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
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
);
193 programming_error (_f ("Vaticana_ligature:"
194 "thickness undefined; assuming 1.4",
196 thickness
= 1.4 * me
->get_paper ()->get_var ("linethickness");
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
);
207 programming_error (_f ("Vaticana_ligature:"
208 "x-offset undefined; assuming 0.0",
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
);
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
);
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
);
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
);
255 programming_error (_f ("Vaticana_ligature: (join_left == 0)"));
256 Real blotdiameter
= (me
->get_paper ()->get_var ("blotdiameter"));
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
);
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 ();
288 MAKE_SCHEME_CALLBACK (Vaticana_ligature
, brew_molecule
, 1);
290 Vaticana_ligature::brew_molecule (SCM
)
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");