]> git.donarmstrong.com Git - lilypond.git/blobdiff - lily/vaticana-ligature.cc
Run `make grand-replace'.
[lilypond.git] / lily / vaticana-ligature.cc
index 916c20e3d890a106118fd256f5b111ac9e57fe78..4995aad2f04ddd0b8920c57789f36516f66bf5fd 100644 (file)
 /*
   vaticana-ligature.cc -- implement Vaticana_ligature
-  
+
   source file of the GNU LilyPond music typesetter
-  
-  (c) 2003 Juergen Reuter <reuter@ipd.uka.de>
+
+  (c) 2003--2008 Juergen Reuter <reuter@ipd.uka.de>
 */
 
-#include <math.h>
-#include "item.hh"
 #include "vaticana-ligature.hh"
+
+#include "bezier.hh"
 #include "font-interface.hh"
-#include "molecule.hh"
+#include "international.hh"
+#include "item.hh"
 #include "lookup.hh"
-#include "staff-symbol-referencer.hh"
 #include "note-head.hh"
-#include "paper-def.hh"
-#include "bezier.hh"
+#include "output-def.hh"
+#include "staff-symbol-referencer.hh"
 #include "warn.hh"
 
-/*
- * TODO: move this function to class Lookup?
- */
-Molecule
-vaticana_brew_flexa (Grob *me,
-                    Real interval,
-                    bool solid,
-                    Real width,
+Stencil
+vaticana_brew_cauda (Grob *me,
+                    int pos,
+                    int delta_pitch,
                     Real thickness,
-                    bool add_stem,
-                    Direction stem_direction)
+                    Real blotdiameter)
 {
-  if (interval >= 0.0)
+  bool on_staffline = Staff_symbol_referencer::on_line (me, pos);
+  int interspaces = Staff_symbol_referencer::line_count (me) - 1;
+  bool above_staff = pos > interspaces;
+
+  if (delta_pitch > -1)
     {
-      me->warning (_ ("ascending vaticana style flexa"));
+      me->programming_error ("flexa cauda: invalid delta_pitch; assuming -1");
+      delta_pitch = -1;
     }
-
-  Real space = Staff_symbol_referencer::staff_space (me);
-  Molecule molecule = Molecule ();
-  Real right_height = 0.6 * space;
-
-  // Compensate thickness that appears to be smaller in steep section
-  // of bend.
-  Real left_height = right_height + min (0.12 * abs(interval), 0.3) * space;
-
-  if (add_stem)
+  Real length;
+  if (on_staffline)
+    {
+      if (delta_pitch >= -1)
+       length = 1.30;
+      else if (delta_pitch >= -2)
+       length = 1.35;
+      else
+       length = 1.85;
+    }
+  else
     {
-      bool consider_interval =
-       stem_direction * interval > 0.0;
-
-      Interval stem_box_x (0, thickness);
-      Interval stem_box_y;
-
-      if (consider_interval)
-       {
-         Real y_length = max (abs(interval)/2.0*space +
-                              (right_height-left_height),
-                              1.2*space);
-         stem_box_y = Interval (0, y_length);
-       }
+      if (delta_pitch >= -1)
+       if (above_staff)
+         length = 1.30;
+       else
+         length = 1.00;
+      else if (delta_pitch >= -2)
+       length = 1.35;
+      else if (delta_pitch >= -3)
+       length = 1.50;
       else
-       stem_box_y = Interval (0, space);
+       length = 1.85;
+    }
+  Box cauda_box (Interval (0, thickness), Interval (-length, 0));
+  return Lookup::round_filled_box (cauda_box, blotdiameter);
+}
 
-      Real y_correction =
-       (stem_direction == UP) ?
-       +0.5*left_height :
-       -0.5*left_height - stem_box_y.length();
+/*
+ * TODO: move this function to class Lookup?
+ */
+Stencil
+vaticana_brew_flexa (Grob *me,
+                    bool solid,
+                    Real line_thickness)
+{
+  Real staff_space = Staff_symbol_referencer::staff_space (me);
+  Stencil stencil;
+  Real right_height = 0.6 * staff_space;
 
-      Box stem_box (stem_box_x, stem_box_y);
-      Molecule stem = Lookup::filledbox (stem_box);
-      stem.translate_axis (y_correction, Y_AXIS);
-      molecule.add_molecule(stem);
+  Real interval;
+  SCM flexa_height_scm = me->get_property ("flexa-height");
+  if (flexa_height_scm != SCM_EOL)
+    interval = scm_to_int (flexa_height_scm);
+  else
+    {
+      me->warning ("Vaticana_ligature: "
+                  + _ ("flexa-height undefined; assuming 0"));
+      interval = 0.0;
     }
 
-  // Compensate optical illusion regarding vertical position of left
-  // and right endings due to curved shape.
-  Real ypos_correction = -0.1*space * sign(interval);
-  Real interval_correction = 0.2*space * sign(interval);
-  Real corrected_interval = interval*space + interval_correction;
-
-  // middle curve of flexa
+  if (interval >= 0.0)
+    me->warning (_ ("ascending vaticana style flexa"));
+
+  Real width = robust_scm2double (me->get_property ("flexa-width"), 2);
+
+  /*
+   * Compensate curve thickness that appears to be smaller in steep
+   * section of bend.
+   */
+  Real left_height
+    = right_height
+    + min (0.12 * abs (interval), 0.3) * staff_space;
+
+  /*
+   * Compensate optical illusion regarding vertical position of left
+   * and right endings due to curved shape.
+   */
+  Real ypos_correction = -0.1 * staff_space * sign (interval);
+  Real interval_correction = 0.2 * staff_space * sign (interval);
+  Real corrected_interval = interval * staff_space + interval_correction;
+
+  /*
+   * middle curve of flexa shape
+   */
   Bezier curve;
   curve.control_[0] = Offset (0.00 * width, 0.0);
   curve.control_[1] = Offset (0.33 * width, corrected_interval / 2.0);
@@ -88,189 +118,159 @@ vaticana_brew_flexa (Grob *me,
   Bezier top_curve = curve, bottom_curve = curve;
   for (int i = 0; i < 4; i++)
     {
-      Real thickness = 0.33 * ((3 - i)*left_height + i*right_height);
-      top_curve.control_[i] += Offset (0, +0.5*thickness);
-      bottom_curve.control_[i] += Offset (0, -0.5*thickness);
+      Real curve_thickness = 0.33 * ((3 - i) * left_height + i * right_height);
+      top_curve.control_[i] += Offset (0, 0.5 * curve_thickness);
+      bottom_curve.control_[i] -= Offset (0, 0.5 * curve_thickness);
     }
 
   if (solid)
     {
-      Molecule solid_head =
-       Lookup::bezier_sandwich (top_curve, bottom_curve);
-      molecule.add_molecule (solid_head);
+      Stencil solid_head
+       Lookup::bezier_sandwich (top_curve, bottom_curve);
+      stencil.add_stencil (solid_head);
     }
   else // outline
     {
       Bezier inner_top_curve = top_curve;
-      inner_top_curve.translate (Offset (0.0, -thickness));
-      Molecule top_edge =
-       Lookup::bezier_sandwich (top_curve, inner_top_curve);
-      molecule.add_molecule(top_edge);
+      inner_top_curve.translate (Offset (0.0, -line_thickness));
+      Stencil top_edge
+       Lookup::bezier_sandwich (top_curve, inner_top_curve);
+      stencil.add_stencil (top_edge);
 
       Bezier inner_bottom_curve = bottom_curve;
-      inner_bottom_curve.translate (Offset (0.0, +thickness));
-      Molecule bottom_edge =
-       Lookup::bezier_sandwich (bottom_curve, inner_bottom_curve);
-      molecule.add_molecule(bottom_edge);
-
-      // TODO: Use horizontal slope with proper slope value rather
-      // than filled box for left edge, since the filled box stands
-      // out from the flexa shape if the interval is big and the line
-      // thickness small.  The difficulty here is to compute a proper
-      // slope value, as it should roughly be equal with the slope of
-      // the left end of the bezier curve.
-      Box left_edge_box (Interval (0, thickness),
-                        Interval (-0.5*left_height, +0.5*left_height));
-      Molecule left_edge = Lookup::filledbox (left_edge_box);
-      molecule.add_molecule(left_edge);
-
-      Box right_edge_box (Interval (-thickness, 0),
-                         Interval (-0.5*right_height, +0.5*right_height));
-      Molecule right_edge = Lookup::filledbox (right_edge_box);
+      inner_bottom_curve.translate (Offset (0.0, +line_thickness));
+      Stencil bottom_edge
+       = Lookup::bezier_sandwich (bottom_curve, inner_bottom_curve);
+      stencil.add_stencil (bottom_edge);
+
+      /*
+       * TODO: Use horizontal slope with proper slope value rather
+       * than filled box for left edge, since the filled box stands
+       * out from the flexa shape if the interval is big and the line
+       * thickness small.  The difficulty here is to compute a proper
+       * slope value, as it should roughly be equal with the slope of
+       * the left end of the bezier curve.
+       */
+      Box left_edge_box (Interval (0, line_thickness),
+                        Interval (-0.5 * left_height, +0.5 * left_height));
+      Stencil left_edge = Lookup::filled_box (left_edge_box);
+      stencil.add_stencil (left_edge);
+
+      Box right_edge_box (Interval (-line_thickness, 0),
+                         Interval (-0.5 * right_height, +0.5 * right_height));
+      Stencil right_edge = Lookup::filled_box (right_edge_box);
       right_edge.translate_axis (width, X_AXIS);
       right_edge.translate_axis (corrected_interval / 2.0, Y_AXIS);
-      molecule.add_molecule(right_edge);
+      stencil.add_stencil (right_edge);
     }
-  molecule.translate_axis (ypos_correction, Y_AXIS);
-  return molecule;
+  stencil.translate_axis (ypos_correction, Y_AXIS);
+  return stencil;
 }
 
-void
-vaticana_add_ledger_lines (Grob *me, Molecule *out, int pos, Real offs,
-                          bool ledger_take_space)
+Stencil
+vaticana_brew_join (Grob *me, int delta_pitch,
+                   Real join_thickness, Real blotdiameter)
 {
-  int interspaces = Staff_symbol_referencer::line_count (me)-1;
-  if (abs (pos) - interspaces > 1)
+  Real staff_space = Staff_symbol_referencer::staff_space (me);
+  if (!delta_pitch)
     {
-      Interval hd = out->extent (X_AXIS);
-      Real left_ledger_protusion = hd.length ()/4;
-      Real right_ledger_protusion = left_ledger_protusion;
-
-      Interval l_extents = Interval (hd[LEFT] - left_ledger_protusion,
-                                    hd[RIGHT] + right_ledger_protusion);
-      Molecule ledger_lines =
-       Note_head::brew_ledger_lines (me, pos, interspaces,
-                                     l_extents,
-                                     ledger_take_space);
-      ledger_lines.translate_axis (offs, Y_AXIS);
-      out->add_molecule (ledger_lines);
+      me->programming_error (_ ("Vaticana_ligature: "
+                               "zero join (delta_pitch == 0)"));
+      return Lookup::blank (Box (Interval (0, 0), Interval (0, 0)));
     }
+  Interval x_extent = Interval (0, join_thickness);
+  Interval y_extent = (delta_pitch > 0)
+    ? Interval (0, delta_pitch * 0.5 * staff_space) : // ascending join
+    Interval (delta_pitch * 0.5 * staff_space, 0); // descending join
+  Box join_box (x_extent, y_extent);
+  return Lookup::round_filled_box (join_box, blotdiameter);
 }
 
-Molecule
-vaticana_brew_primitive (Grob *me, bool ledger_take_space)
+Stencil
+vaticana_brew_primitive (Grob *me)
 {
-  SCM glyph_name_scm = me->get_grob_property ("glyph-name");
+  SCM glyph_name_scm = me->get_property ("glyph-name");
   if (glyph_name_scm == SCM_EOL)
     {
-      programming_error ("Vaticana_ligature:"
-                        "undefined glyph-name -> ignoring grob");
-      return Molecule ();
+      me->programming_error ("Vaticana_ligature: "
+                            "undefined glyph-name -> ignoring grob");
+      return Lookup::blank (Box (Interval (0, 0), Interval (0, 0)));
     }
 
-  String glyph_name = ly_scm2string (glyph_name_scm);
-  if (!String::compare (glyph_name, ""))
-    {
-      // empty head (typically, this is the right side of porrectus
-      // shape, which is already typeset by the associated left side
-      // head); nothing left to do
-      return Molecule ();
-    }
+  string glyph_name = ly_scm2string (glyph_name_scm);
 
-  Molecule out;
-  int porrectus_height = 0;
-  Real thickness = 0.0;
-  Real porrectus_width = 0.0;
-  Real staff_space = Staff_symbol_referencer::staff_space (me);
+  Stencil out;
+  Real thickness = robust_scm2double (me->get_property ("thickness"), 1);
 
-  SCM thickness_scm = me->get_grob_property ("thickness");
-  if (thickness_scm != SCM_EOL)
-    {
-      thickness = gh_scm2double (thickness_scm);
-    }
+  Real line_thickness
+    = thickness * me->layout ()->get_dimension (ly_symbol2scm ("line-thickness"));
+
+  Real blotdiameter
+    = (me->layout ()->get_dimension (ly_symbol2scm ("blot-diameter")));
+
+  int pos = Staff_symbol_referencer::get_rounded_position (me);
+
+  SCM delta_pitch_scm = me->get_property ("delta-position");
+  int delta_pitch;
+  if (delta_pitch_scm != SCM_EOL)
+    delta_pitch = scm_to_int (delta_pitch_scm);
   else
-    {
-      programming_error (_f ("Vaticana_ligature:"
-                            "thickness undefined; assuming 1.4",
-                            me));
-      thickness = 1.4 * me->get_paper ()->get_var ("linethickness");
-    }
+    delta_pitch = 0;
+
+  Real x_offset = robust_scm2double (me->get_property ("x-offset"), 0);
 
-  Real x_offset = 0.0;
-  SCM x_offset_scm = me->get_grob_property ("x-offset");
-  if (x_offset_scm != SCM_EOL)
+  bool add_stem = to_boolean (me->get_property ("add-stem"));
+  bool add_cauda = to_boolean (me->get_property ("add-cauda"));
+  bool add_join = to_boolean (me->get_property ("add-join"));
+
+  if (glyph_name == "")
     {
-      x_offset = gh_scm2double (x_offset_scm);
+      /*
+       * This is an empty head.  This typically applies for the right
+       * side of a curved flexa shape, which is already typeset by the
+       * associated left side head.  The only possible thing left to
+       * do is to draw a vertical join to the next head.  (Urgh: need
+       * flexa_width.)
+       */
+      Real staff_space = Staff_symbol_referencer::staff_space (me);
+      Real flexa_width = robust_scm2double (me->get_property ("flexa-width"), 2) * staff_space;
+      out
+       = Lookup::blank (Box (Interval (0, 0.5 * flexa_width), Interval (0, 0)));
     }
+  else if (glyph_name == "flexa")
+    out = vaticana_brew_flexa (me, true, line_thickness);
   else
     {
-      programming_error (_f ("Vaticana_ligature:"
-                            "x-offset undefined; assuming 0.0",
-                            me));
+      out
+       = Font_interface::get_default_font (me)->
+       find_by_name ("noteheads.s" + glyph_name);
     }
+  out.translate_axis (x_offset, X_AXIS);
+  Real head_width = out.extent (X_AXIS).length ();
 
-  if (!String::compare (glyph_name, "porrectus"))
+  if (add_cauda)
     {
-      SCM porrectus_height_scm = me->get_grob_property ("porrectus-height");
-      if (porrectus_height_scm != SCM_EOL)
-       {
-         porrectus_height = gh_scm2int (porrectus_height_scm);
-       }
-      else
-       {
-         me->warning ("Vaticana_ligature: "
-                      "porrectus-height undefined; assuming 0");
-       }
-
-      SCM porrectus_width_scm = me->get_grob_property ("porrectus-width");
-      if (porrectus_width_scm != SCM_EOL)
-       {
-         porrectus_width = gh_scm2double (porrectus_width_scm);
-       }
-      else
-       {
-         me->warning ("Vaticana_ligature:"
-                      "porrectus-width undefined; assuming 2.0");
-         porrectus_width = 2.0 * staff_space;
-       }
-
-      bool add_stem = to_boolean (me->get_grob_property ("add-stem"));
-      out = vaticana_brew_flexa (me, porrectus_height, true,
-                                porrectus_width, thickness, add_stem, DOWN);
-    }
-  else
-    {
-      Molecule mol =
-       Font_interface::get_default_font (me)->
-       find_by_name ("noteheads-" + glyph_name);
-      mol.translate_axis (x_offset, X_AXIS);
-      out.add_molecule (mol);
+      Stencil cauda
+       = vaticana_brew_cauda (me, pos, delta_pitch,
+                              line_thickness, blotdiameter);
+      out.add_stencil (cauda);
     }
 
-  SCM join_left_scm = me->get_grob_property ("join-left");
-  if (join_left_scm != SCM_EOL)
+  if (add_stem)
     {
-      int join_left = gh_scm2int (join_left_scm);
-      if (!join_left)
-       programming_error (_f ("Vaticana_ligature: (join_left == 0)"));
-      Real blotdiameter = (me->get_paper ()->get_var ("blotdiameter"));
-      Interval x_extent =
-       Interval (-0.5 * thickness, +0.5 * thickness);
-      Interval y_extent = (join_left > 0) ?
-       Interval (-join_left * 0.5 * staff_space, 0) : // ascending join
-       Interval (0, -join_left * 0.5 * staff_space); // descending join
-      Box stem_box (x_extent, y_extent);
-
-      Molecule stem = Lookup::roundfilledbox (stem_box, blotdiameter);
-      out.add_molecule (stem);
+      Stencil stem
+       = vaticana_brew_cauda (me, pos, -1,
+                              line_thickness, blotdiameter);
+      stem.translate_axis (head_width - line_thickness, X_AXIS);
+      out.add_stencil (stem);
     }
 
-  int pos = (int)rint (Staff_symbol_referencer::get_position (me));
-  vaticana_add_ledger_lines(me, &out, pos, 0, ledger_take_space);
-  if (!String::compare (glyph_name, "porrectus"))
+  if (add_join)
     {
-      pos += porrectus_height;
-      vaticana_add_ledger_lines(me, &out, pos, 0.5*porrectus_height, ledger_take_space);
+      Stencil join
+       = vaticana_brew_join (me, delta_pitch, line_thickness, blotdiameter);
+      join.translate_axis (head_width - line_thickness, X_AXIS);
+      out.add_stencil (join);
     }
 
   return out;
@@ -281,18 +281,28 @@ SCM
 Vaticana_ligature::brew_ligature_primitive (SCM smob)
 {
   Grob *me = unsmob_grob (smob);
-  SCM primitive = vaticana_brew_primitive (me, false).smobbed_copy ();
+  SCM primitive = vaticana_brew_primitive (me).smobbed_copy ();
   return primitive;
 }
 
-MAKE_SCHEME_CALLBACK (Vaticana_ligature, brew_molecule, 1);
+MAKE_SCHEME_CALLBACK (Vaticana_ligature, print, 1);
 SCM
-Vaticana_ligature::brew_molecule (SCM)
+Vaticana_ligature::print (SCM)
 {
   return SCM_EOL;
 }
 
-ADD_INTERFACE (Vaticana_ligature, "vaticana-ligature-interface",
-              "A vaticana style gregorian ligature",
-              "glyph-name porrectus-height porrectus-width thickness join-left "
-              "add-stem x-offset ligature-primitive-callback");
+ADD_INTERFACE (Vaticana_ligature,
+              "A vaticana style Gregorian ligature.",
+
+              /* properties */
+              "glyph-name "
+              "flexa-height "
+              "flexa-width "
+              "thickness "
+              "add-cauda "
+              "add-stem "
+              "add-join "
+              "delta-position "
+              "x-offset "
+              );