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
,
28 Direction stem_direction
)
30 Real staff_space
= Staff_symbol_referencer::staff_space (me
);
31 Molecule molecule
= Molecule ();
32 Real right_height
= 0.6 * staff_space
;
35 SCM flexa_height_scm
= me
->get_grob_property ("flexa-height");
36 if (flexa_height_scm
!= SCM_EOL
)
38 interval
= gh_scm2int (flexa_height_scm
);
42 me
->warning ("Vaticana_ligature: "
43 "flexa-height undefined; assuming 0");
49 me
->warning (_ ("ascending vaticana style flexa"));
53 SCM flexa_width_scm
= me
->get_grob_property ("flexa-width");
54 if (flexa_width_scm
!= SCM_EOL
)
56 width
= gh_scm2double (flexa_width_scm
);
60 me
->warning ("Vaticana_ligature:"
61 "flexa-width undefined; assuming 2.0");
62 width
= 2.0 * staff_space
;
65 bool add_stem
= to_boolean (me
->get_grob_property ("add-stem"));
67 // Compensate thickness that appears to be smaller in steep section
71 min (0.12 * abs(interval
), 0.3) * staff_space
;
75 bool consider_interval
=
76 stem_direction
* interval
> 0.0;
78 Interval
stem_box_x (0, thickness
);
81 if (consider_interval
)
83 Real y_length
= max (abs(interval
)/2.0*staff_space
+
84 (right_height
-left_height
),
86 stem_box_y
= Interval (0, y_length
);
89 stem_box_y
= Interval (0, staff_space
);
92 (stem_direction
== UP
) ?
94 -0.5*left_height
- stem_box_y
.length();
96 Box
stem_box (stem_box_x
, stem_box_y
);
97 Molecule stem
= Lookup::filledbox (stem_box
);
98 stem
.translate_axis (y_correction
, Y_AXIS
);
99 molecule
.add_molecule(stem
);
102 // Compensate optical illusion regarding vertical position of left
103 // and right endings due to curved shape.
104 Real ypos_correction
= -0.1*staff_space
* sign(interval
);
105 Real interval_correction
= 0.2*staff_space
* sign(interval
);
106 Real corrected_interval
= interval
*staff_space
+ interval_correction
;
108 // middle curve of flexa shape
110 curve
.control_
[0] = Offset (0.00 * width
, 0.0);
111 curve
.control_
[1] = Offset (0.33 * width
, corrected_interval
/ 2.0);
112 curve
.control_
[2] = Offset (0.66 * width
, corrected_interval
/ 2.0);
113 curve
.control_
[3] = Offset (1.00 * width
, corrected_interval
/ 2.0);
115 Bezier top_curve
= curve
, bottom_curve
= curve
;
116 for (int i
= 0; i
< 4; i
++)
118 Real thickness
= 0.33 * ((3 - i
)*left_height
+ i
*right_height
);
119 top_curve
.control_
[i
] += Offset (0, +0.5*thickness
);
120 bottom_curve
.control_
[i
] += Offset (0, -0.5*thickness
);
125 Molecule solid_head
=
126 Lookup::bezier_sandwich (top_curve
, bottom_curve
);
127 molecule
.add_molecule (solid_head
);
131 Bezier inner_top_curve
= top_curve
;
132 inner_top_curve
.translate (Offset (0.0, -thickness
));
134 Lookup::bezier_sandwich (top_curve
, inner_top_curve
);
135 molecule
.add_molecule(top_edge
);
137 Bezier inner_bottom_curve
= bottom_curve
;
138 inner_bottom_curve
.translate (Offset (0.0, +thickness
));
139 Molecule bottom_edge
=
140 Lookup::bezier_sandwich (bottom_curve
, inner_bottom_curve
);
141 molecule
.add_molecule(bottom_edge
);
143 // TODO: Use horizontal slope with proper slope value rather
144 // than filled box for left edge, since the filled box stands
145 // out from the flexa shape if the interval is big and the line
146 // thickness small. The difficulty here is to compute a proper
147 // slope value, as it should roughly be equal with the slope of
148 // the left end of the bezier curve.
149 Box
left_edge_box (Interval (0, thickness
),
150 Interval (-0.5*left_height
, +0.5*left_height
));
151 Molecule left_edge
= Lookup::filledbox (left_edge_box
);
152 molecule
.add_molecule(left_edge
);
154 Box
right_edge_box (Interval (-thickness
, 0),
155 Interval (-0.5*right_height
, +0.5*right_height
));
156 Molecule right_edge
= Lookup::filledbox (right_edge_box
);
157 right_edge
.translate_axis (width
, X_AXIS
);
158 right_edge
.translate_axis (corrected_interval
/ 2.0, Y_AXIS
);
159 molecule
.add_molecule(right_edge
);
161 molecule
.translate_axis (ypos_correction
, Y_AXIS
);
166 vaticana_add_ledger_lines (Grob
*me
, Molecule
*out
, int pos
, Real offs
,
167 bool ledger_take_space
)
169 int interspaces
= Staff_symbol_referencer::line_count (me
)-1;
170 if (abs (pos
) - interspaces
> 1)
172 Interval hd
= out
->extent (X_AXIS
);
173 Real left_ledger_protusion
= hd
.length ()/4;
174 Real right_ledger_protusion
= left_ledger_protusion
;
176 Interval l_extents
= Interval (hd
[LEFT
] - left_ledger_protusion
,
177 hd
[RIGHT
] + right_ledger_protusion
);
178 Molecule ledger_lines
=
179 Note_head::brew_ledger_lines (me
, pos
, interspaces
,
182 ledger_lines
.translate_axis (offs
, Y_AXIS
);
183 out
->add_molecule (ledger_lines
);
188 vaticana_brew_primitive (Grob
*me
, bool ledger_take_space
)
190 SCM glyph_name_scm
= me
->get_grob_property ("glyph-name");
191 if (glyph_name_scm
== SCM_EOL
)
193 programming_error ("Vaticana_ligature:"
194 "undefined glyph-name -> ignoring grob");
198 String glyph_name
= ly_scm2string (glyph_name_scm
);
199 if (!String::compare (glyph_name
, ""))
201 // empty head (typically, this is the right side of flexa shape,
202 // which is already typeset by the associated left side head);
203 // nothing left to do
208 int flexa_height
= 0;
209 Real thickness
= 0.0;
210 Real staff_space
= Staff_symbol_referencer::staff_space (me
);
212 SCM thickness_scm
= me
->get_grob_property ("thickness");
213 if (thickness_scm
!= SCM_EOL
)
215 thickness
= gh_scm2double (thickness_scm
);
219 programming_error (_f ("Vaticana_ligature:"
220 "thickness undefined; assuming 1.4",
222 thickness
= 1.4 * me
->get_paper ()->get_realvar (ly_symbol2scm ("linethickness"));
226 SCM x_offset_scm
= me
->get_grob_property ("x-offset");
227 if (x_offset_scm
!= SCM_EOL
)
229 x_offset
= gh_scm2double (x_offset_scm
);
233 programming_error (_f ("Vaticana_ligature:"
234 "x-offset undefined; assuming 0.0",
238 if (!String::compare (glyph_name
, "flexa"))
240 out
= vaticana_brew_flexa (me
, true, thickness
, DOWN
);
245 Font_interface::get_default_font (me
)->
246 find_by_name ("noteheads-" + glyph_name
);
247 mol
.translate_axis (x_offset
, X_AXIS
);
248 out
.add_molecule (mol
);
251 if (to_boolean (me
->get_grob_property ("join-left")))
253 SCM delta_pitch_scm
= me
->get_grob_property ("delta-pitch");
254 if (delta_pitch_scm
!= SCM_EOL
)
256 int delta_pitch
= gh_scm2int (delta_pitch_scm
);
258 programming_error (_f ("Vaticana_ligature: (delta_pitch == 0)"));
259 Real blotdiameter
= (me
->get_paper ()->get_realvar (ly_symbol2scm ("blotdiameter")));
260 Interval x_extent
= Interval (0, thickness
);
261 Interval y_extent
= (delta_pitch
> 0) ?
262 Interval (-delta_pitch
* 0.5 * staff_space
, 0) : // ascending join
263 Interval (0, -delta_pitch
* 0.5 * staff_space
); // descending join
264 Box
stem_box (x_extent
, y_extent
);
266 Molecule stem
= Lookup::round_filled_box (stem_box
, blotdiameter
);
267 out
.add_molecule (stem
);
271 programming_error (_f ("Vaticana_ligature:"
272 "delta-pitch -> ignoring join",
277 int pos
= (int)rint (Staff_symbol_referencer::get_position (me
));
278 vaticana_add_ledger_lines(me
, &out
, pos
, 0, ledger_take_space
);
279 if (!String::compare (glyph_name
, "flexa"))
282 vaticana_add_ledger_lines(me
, &out
, pos
, 0.5*flexa_height
, ledger_take_space
);
288 MAKE_SCHEME_CALLBACK (Vaticana_ligature
, brew_ligature_primitive
, 1);
290 Vaticana_ligature::brew_ligature_primitive (SCM smob
)
292 Grob
*me
= unsmob_grob (smob
);
293 SCM primitive
= vaticana_brew_primitive (me
, false).smobbed_copy ();
297 MAKE_SCHEME_CALLBACK (Vaticana_ligature
, brew_molecule
, 1);
299 Vaticana_ligature::brew_molecule (SCM
)
304 ADD_INTERFACE (Vaticana_ligature
, "vaticana-ligature-interface",
305 "A vaticana style gregorian ligature",
306 "glyph-name flexa-height flexa-width thickness join-left "
307 "delta-pitch add-stem x-offset ligature-primitive-callback");