2 porrectus.cc -- implement Porrectus
4 Copyright (C) 2001 Juergen Reuter
6 written for the GNU LilyPond music typesetter
8 TODO: --> see porrectus-engraver.cc
11 #include "staff-symbol-referencer.hh"
12 #include "porrectus.hh"
14 #include "molecule.hh"
18 #include "dimensions.hh"
19 #include "direction.hh"
21 #include "font-interface.hh"
22 #include "paper-def.hh"
23 #include "math.h" // rint
26 Porrectus::set_left_head (Grob *me, Item *left_head)
30 me->set_grob_property ("left-head", left_head->self_scm());
34 programming_error (_ ("(left_head == 0)"));
35 me->set_grob_property ("left-head", SCM_EOL);
40 Porrectus::get_left_head (Grob *me)
42 SCM left_head_scm = me->get_grob_property ("left-head");
43 if (left_head_scm == SCM_EOL)
45 programming_error (_ ("undefined left_head"));
50 Item *left_head = dynamic_cast<Item*> (unsmob_grob (left_head_scm));
56 Porrectus::set_right_head (Grob *me, Item *right_head)
60 me->set_grob_property ("right-head", right_head->self_scm());
64 programming_error (_ ("(right_head == 0)"));
65 me->set_grob_property ("right-head", SCM_EOL);
70 Porrectus::get_right_head (Grob *me)
72 SCM right_head_scm = me->get_grob_property ("right-head");
73 if (right_head_scm == SCM_EOL)
75 programming_error (_ ("undefined right_head"));
80 Item *right_head = dynamic_cast<Item*> (unsmob_grob (right_head_scm));
85 // Uugh. The following two functions are almost duplicated code from
86 // custos.cc, which itself is similar to code in note-head.cc. Maybe
87 // this should be moved to staff-symbol-referencer.cc?
89 Porrectus::create_ledger_line (Interval x_extent, Grob *me)
92 Molecule slice = Font_interface::get_default_font (me)->find_by_name ("noteheads-ledgerending");
93 Interval slice_x_extent = slice.extent (X_AXIS);
94 Interval slice_y_extent = slice.extent (Y_AXIS);
96 // Create left ending of ledger line.
97 Molecule left_ending = slice;
98 left_ending.translate_axis (x_extent[LEFT] - slice_x_extent[LEFT], X_AXIS);
99 if (x_extent.length () > slice_x_extent.length ())
100 line.add_molecule (left_ending);
102 // Create right ending of ledger line.
103 Molecule right_ending = slice;
104 right_ending.translate_axis (x_extent[RIGHT] - slice_x_extent[RIGHT],
106 line.add_molecule (right_ending);
108 // Fill out space between left and right ending of ledger line by
109 // lining up a series of slices in a row between them.
110 Molecule fill_out_slice = left_ending;
111 Real thick = slice_y_extent.length ();
112 Real delta_x = slice_x_extent.length () - thick;
113 Real xpos = x_extent [LEFT] + 2*delta_x + thick/2; // TODO: check: thick*2?
114 while (xpos <= x_extent[RIGHT])
116 fill_out_slice.translate_axis (delta_x, X_AXIS);
117 line.add_molecule (fill_out_slice);
125 Porrectus::create_streepjes (Grob *me,
130 Real inter_f = Staff_symbol_referencer::staff_space (me)/2;
131 int streepjes_i = abs (pos) < interspaces
133 : (abs (pos) - interspaces) /2;
134 Molecule molecule = Molecule();
137 Direction dir = (Direction)sign (pos);
138 Molecule ledger_line (create_ledger_line (extent, me));
139 ledger_line.set_empty (true);
140 Real offs = (Staff_symbol_referencer::on_staffline (me, pos))
143 for (int i = 0; i < streepjes_i; i++)
145 Molecule streep (ledger_line);
146 streep.translate_axis (-dir * inter_f * i * 2 + offs,
148 molecule.add_molecule (streep);
154 MAKE_SCHEME_CALLBACK (Porrectus,brew_molecule,1);
156 Porrectus::brew_molecule (SCM smob)
158 Item *me = (Item *)unsmob_grob (smob);
160 SCM scm_style = me->get_grob_property ("style");
162 if ((gh_symbol_p (scm_style)) && (scm_style != SCM_EOL))
163 style = ly_scm2string (scm_symbol_to_string (scm_style));
165 warning (_ ("porrectus style undefined; using mensural"));
169 bool solid = to_boolean (me->get_grob_property ("solid"));
170 bool add_stem = to_boolean (me->get_grob_property ("add-stem"));
172 SCM stem_direction_scm = me->get_grob_property ("stem-direction");
173 Direction stem_direction =
174 gh_number_p (stem_direction_scm) ? to_dir (stem_direction_scm) : DOWN;
176 stem_direction = DOWN;
178 Item *left_head = get_left_head (me);
179 Item *right_head = get_right_head (me);
180 if (!left_head || !right_head)
182 warning (_ ("junking lonely porrectus"));
187 Real left_position_f = Staff_symbol_referencer::position_f (left_head);
188 Real right_position_f = Staff_symbol_referencer::position_f (right_head);
189 Real interval = right_position_f - left_position_f;
193 SCM line_thickness_scm = me->get_grob_property ("line-thickness");
195 if (gh_number_p (line_thickness_scm))
197 line_thickness = gh_scm2double (line_thickness_scm);
201 line_thickness = 1.0;
204 line_thickness * me->paper_l ()->get_var ("stafflinethickness");
206 SCM porrectus_width_scm = me->get_grob_property ("porrectus-width");
207 Real porrectus_width;
208 if (gh_number_p (porrectus_width_scm))
210 porrectus_width = gh_scm2double (porrectus_width_scm);
214 porrectus_width = 2.4;
216 Real width = porrectus_width * Staff_symbol_referencer::staff_space (me);
218 if (String::compare_i (style, "vaticana") == 0)
219 molecule = brew_vaticana_molecule (me, interval,
220 solid, width, thickness,
221 add_stem, stem_direction);
222 else if (String::compare_i (style, "mensural") == 0)
223 molecule = brew_mensural_molecule (me, interval,
224 solid, width, thickness,
225 add_stem, stem_direction);
229 Real space = Staff_symbol_referencer::staff_space (me);
230 Real head_extent = molecule.extent (X_AXIS).length ();
231 Interval extent (-0.2 * head_extent, 1.2 * head_extent);
232 int interspaces = Staff_symbol_referencer::line_count (me)-1;
234 molecule.translate_axis (left_position_f * space/2, Y_AXIS);
236 Molecule left_head_streepjes =
237 create_streepjes (me, (int)rint (left_position_f), interspaces, extent);
238 left_head_streepjes.translate_axis (left_position_f * space/2, Y_AXIS);
239 molecule.add_molecule (left_head_streepjes);
241 Molecule right_head_streepjes =
242 create_streepjes (me, (int)rint (right_position_f), interspaces, extent);
243 right_head_streepjes.translate_axis (right_position_f * space/2, Y_AXIS);
244 molecule.add_molecule (right_head_streepjes);
246 return molecule.smobbed_copy();
250 Porrectus::brew_vaticana_molecule (Item *me,
256 Direction stem_direction)
258 Real space = Staff_symbol_referencer::staff_space (me);
259 Molecule molecule = Molecule ();
263 warning (_ ("ascending vaticana style porrectus"));
268 bool consider_interval =
269 stem_direction * interval > 0.0;
271 Interval stem_box_x (-thickness/2, +thickness/2);
274 if (consider_interval)
276 Real y_length = interval / 2.0;
277 if (y_length < 1.2 * space)
278 y_length = 1.2 * space;
279 stem_box_y = Interval (0, y_length);
282 stem_box_y = Interval (0, space);
285 (stem_direction == UP) ?
287 - 0.3 * space - stem_box_y.length();
289 Box stem_box (stem_box_x, stem_box_y);
290 Molecule stem = Lookup::filledbox (stem_box);
291 stem.translate_axis (y_correction, Y_AXIS);
292 molecule.add_molecule(stem);
295 Box vertical_edge (Interval (-thickness/2, +thickness/2),
296 Interval (-4*thickness/2, +4*thickness/2));
297 Molecule left_edge = Lookup::filledbox (vertical_edge);
298 Molecule right_edge = Lookup::filledbox (vertical_edge);
299 right_edge.translate_axis (width, X_AXIS);
300 right_edge.translate_axis (interval / 2.0, Y_AXIS);
301 molecule.add_molecule(left_edge);
302 molecule.add_molecule(right_edge);
305 bezier.control_[0] = Offset (0.00 * width, 0.0);
306 bezier.control_[1] = Offset (0.33 * width, interval / 2.0);
307 bezier.control_[2] = Offset (0.66 * width, interval / 2.0);
308 bezier.control_[3] = Offset (1.00 * width, interval / 2.0);
311 slice = Lookup::slur (bezier, 0.0, thickness);
312 slice.translate_axis (-3 * thickness/2, Y_AXIS);
313 molecule.add_molecule (slice);
315 for (int i = -2; i < +2; i++)
317 slice = Lookup::slur (bezier, 0.0, thickness);
318 slice.translate_axis (i * thickness/2, Y_AXIS);
319 molecule.add_molecule (slice);
321 slice = Lookup::slur (bezier, 0.0, thickness);
322 slice.translate_axis (+3 * thickness/2, Y_AXIS);
323 molecule.add_molecule (slice);
329 Porrectus::brew_mensural_molecule (Item *me,
335 Direction stem_direction)
337 Real space = Staff_symbol_referencer::staff_space (me);
338 Molecule molecule = Molecule ();
342 // Uugh. This is currently the same as in
343 // brew_vaticana_molecule, but may eventually be changed.
345 bool consider_interval =
346 stem_direction * interval > 0.0;
348 Interval stem_box_x (0, thickness);
351 if (consider_interval)
353 Real y_length = interval / 2.0;
354 if (y_length < 1.2 * space)
355 y_length = 1.2 * space;
356 stem_box_y = Interval (0, y_length);
359 stem_box_y = Interval (0, space);
362 (stem_direction == UP) ?
364 - 0.3 * space - stem_box_y.length();
366 Box stem_box (stem_box_x, stem_box_y);
367 Molecule stem = Lookup::filledbox (stem_box);
368 stem.translate_axis (y_correction, Y_AXIS);
369 molecule.add_molecule(stem);
372 Real slope = (interval / 2.0) / width;
374 // Compensate optical illusion regarding vertical position of left
375 // and right endings due to slope.
376 Real ypos_correction = -0.1*space * sign(slope);
377 Real slope_correction = 0.2*space * sign(slope);
378 Real corrected_slope = slope + slope_correction/width;
382 Molecule solid_head =
383 brew_horizontal_slope (width, corrected_slope, 0.6*space);
384 molecule.add_molecule (solid_head);
389 brew_horizontal_slope (thickness, corrected_slope, 0.6*space);
390 molecule.add_molecule(left_edge);
392 Molecule right_edge =
393 brew_horizontal_slope (thickness, corrected_slope, 0.6*space);
394 right_edge.translate_axis (width-thickness, X_AXIS);
395 right_edge.translate_axis (corrected_slope * (width-thickness), Y_AXIS);
396 molecule.add_molecule(right_edge);
398 Molecule bottom_edge =
399 brew_horizontal_slope (width, corrected_slope, thickness);
400 bottom_edge.translate_axis (-0.3*space, Y_AXIS);
401 molecule.add_molecule (bottom_edge);
404 brew_horizontal_slope (width, corrected_slope, thickness);
405 top_edge.translate_axis (+0.3*space, Y_AXIS);
406 molecule.add_molecule (top_edge);
408 molecule.translate_axis (ypos_correction, Y_AXIS);
422 * (0,0) x /slope=dy/dx
430 Porrectus::brew_horizontal_slope(Real width, Real slope, Real thickness)
432 SCM width_scm = gh_double2scm (width);
433 SCM slope_scm = gh_double2scm (slope);
434 SCM thickness_scm = gh_double2scm (thickness);
435 SCM horizontal_slope = scm_list_n (ly_symbol2scm ("beam"),
436 width_scm, slope_scm,
437 thickness_scm, SCM_UNDEFINED);
438 Box b (Interval (0, width),
439 Interval (-thickness/2, thickness/2 + width*slope));
440 return Molecule (b, horizontal_slope);