]> git.donarmstrong.com Git - lilypond.git/blobdiff - lily/porrectus.cc
* VERSION (MY_PATCH_LEVEL): make 1.7.0
[lilypond.git] / lily / porrectus.cc
index a227330e0013daf4015955561de7393037b66d4f..8b05d26b76ffdeb1a9b0b2a7368f605401643179 100644 (file)
@@ -1,7 +1,7 @@
 /*
   porrectus.cc -- implement Porrectus
 
-  Copyright (C) 2001 Juergen Reuter
+  Copyright (c) 2001--2002  Juergen Reuter
 
   written for the GNU LilyPond music typesetter
 
 #include "molecule.hh"
 #include "pitch.hh"
 #include "lookup.hh"
-#include "debug.hh"
+#include "warn.hh"
 #include "dimensions.hh"
 #include "direction.hh"
 #include "bezier.hh"
 #include "font-interface.hh"
 #include "paper-def.hh"
+#include "note-head.hh"
 #include "math.h" // rint
 
 void
@@ -47,7 +48,7 @@ Porrectus::get_left_head (Grob *me)
     }
   else
     {
-      Item *left_head = dynamic_cast<Item*> (unsmob_grob (left_head_scm));
+      Item *left_head = unsmob_item (left_head_scm);
       return left_head;
     }
 }
@@ -77,120 +78,100 @@ Porrectus::get_right_head (Grob *me)
     }
   else
     {
-      Item *right_head = dynamic_cast<Item*> (unsmob_grob (right_head_scm));
+      Item *right_head = unsmob_item (right_head_scm);
       return right_head;
     }
 }
 
-// Uugh.  The following two functions are almost duplicated code from
-// custos.cc, which itself is similar to code in note-head.cc.  Maybe
-// this should be moved to staff-symbol-referencer.cc?
-Molecule
-Porrectus::create_ledger_line (Interval x_extent, Grob *me) 
-{
-  Molecule line;
-  Molecule slice = Font_interface::get_default_font (me)->find_by_name ("noteheads-ledgerending");
-  Interval slice_x_extent = slice.extent (X_AXIS);
-  Interval slice_y_extent = slice.extent (Y_AXIS);
-
-  // Create left ending of ledger line.
-  Molecule left_ending = slice;
-  left_ending.translate_axis (x_extent[LEFT] - slice_x_extent[LEFT], X_AXIS);
-  if (x_extent.length () > slice_x_extent.length ())
-    line.add_molecule (left_ending);
-
-  // Create right ending of ledger line.
-  Molecule right_ending = slice;
-  right_ending.translate_axis (x_extent[RIGHT] - slice_x_extent[RIGHT],
-                              X_AXIS);
-  line.add_molecule (right_ending);
-
-  // Fill out space between left and right ending of ledger line by
-  // lining up a series of slices in a row between them.
-  Molecule fill_out_slice = left_ending;
-  Real thick = slice_y_extent.length ();
-  Real delta_x = slice_x_extent.length () - thick;
-  Real xpos = x_extent [LEFT] + 2*delta_x + thick/2; // TODO: check: thick*2?
-  while (xpos <= x_extent[RIGHT])
-    {
-      fill_out_slice.translate_axis (delta_x, X_AXIS);
-      line.add_molecule (fill_out_slice);
-      xpos += delta_x;
-    }
-
-  return line;
-}
-
-Molecule
-Porrectus::create_streepjes (Grob *me,
-                            int pos,
-                            int interspaces,
-                            Interval extent)
-{
-  Real inter_f = Staff_symbol_referencer::staff_space (me)/2;
-  int streepjes_i = abs (pos) < interspaces
-    ? 0
-    : (abs (pos) - interspaces) /2;
-  Molecule molecule = Molecule();
-  if (streepjes_i) 
-    {
-      Direction dir = (Direction)sign (pos);
-      Molecule ledger_line (create_ledger_line (extent, me));
-      ledger_line.set_empty (true);
-      Real offs = (Staff_symbol_referencer::on_staffline (me, pos))
-       ? 0.0
-       : -dir * inter_f;
-      for (int i = 0; i < streepjes_i; i++)
-       {
-         Molecule streep (ledger_line);
-         streep.translate_axis (-dir * inter_f * i * 2 + offs,
-                                Y_AXIS);
-         molecule.add_molecule (streep);
-       }
-    }
-  return molecule;
-}
-
 MAKE_SCHEME_CALLBACK (Porrectus,brew_molecule,1);
 SCM 
 Porrectus::brew_molecule (SCM smob)
 {
   Item *me = (Item *)unsmob_grob (smob);
 
+  Item *left_head = get_left_head (me);
+  Item *right_head = get_right_head (me);
+  if (!left_head || !right_head)
+    {
+      me->warning (_ ("junking lonely porrectus"));
+      me->suicide ();
+      return SCM_EOL;
+    }
+
   SCM scm_style = me->get_grob_property ("style");
   String style;
   if ((gh_symbol_p (scm_style)) && (scm_style != SCM_EOL))
     style = ly_scm2string (scm_symbol_to_string (scm_style));
   else {
-    warning (_ ("porrectus style undefined; using mensural"));
+    me->warning (_ ("porrectus style undefined; using mensural"));
     style = "mensural";
   }
 
   bool solid = to_boolean (me->get_grob_property ("solid"));
   bool add_stem = to_boolean (me->get_grob_property ("add-stem"));
 
-  SCM stem_direction_scm = me->get_grob_property ("stem-direction");
+  /*
+   * This property is called stem-direction (rather than direction)
+   * since it only refers to this grob's stem (or, more precisely, its
+   * "cauda"), but not the grob as a whole.
+   */
+  SCM stem_direction_scm = me->get_grob_property ("direction");
   Direction stem_direction =
     gh_number_p (stem_direction_scm) ? to_dir (stem_direction_scm) : DOWN;
   if (!stem_direction)
     stem_direction = DOWN;
 
-  Item *left_head = get_left_head (me);
-  Item *right_head = get_right_head (me);
-  if (!left_head || !right_head)
+  /*
+    TODO: revise name.
+   */
+  bool auto_properties = to_boolean (me->get_grob_property ("auto-properties"));
+  if (auto_properties)
+      // determine add_stem and stem_direction automatically from durations
     {
-      warning (_ ("junking lonely porrectus"));
-      me->suicide ();
-      return SCM_EOL;
+      if (String::compare (style, "mensural") != 0)
+       me->warning (String("auto-property should be used for\r\n") +
+                String("mensural style porrectus only; trying anyway"));
+
+      int left_duration =
+         gh_scm2int (left_head->get_grob_property ("duration-log"));
+      int right_duration =
+         gh_scm2int (right_head->get_grob_property ("duration-log"));
+
+      if ((left_duration == -1) && (right_duration == -1))
+        {
+         // brevis -- brevis:
+         // cum proprietate et sine perfectione (c.s.)
+         add_stem = true;
+         stem_direction = DOWN;
+       }
+      else if ((left_duration == -2) && (right_duration == -1))
+        {
+         // longa -- brevis:
+         // sine proprietate et sine perfectione (s.s.)
+         add_stem = false;
+       }
+      else if ((left_duration == 0) && (right_duration == 0))
+        {
+         // semibrevis -- semibrevis:
+         // cum opposita proprietate (c.o.p.)
+         add_stem = true;
+         stem_direction = UP;
+       }
+      else
+        {
+         me->warning (String("auto-property: failed determining porrectus\r\n") +
+                  String("properties due to improper durations; ") +
+                  String("using user-supplied properties"));
+       }
     }
 
-  Real left_position_f = Staff_symbol_referencer::position_f (left_head);
-  Real right_position_f = Staff_symbol_referencer::position_f (right_head);
+  Real left_position_f = Staff_symbol_referencer::get_position (left_head);
+  Real right_position_f = Staff_symbol_referencer::get_position (right_head);
   Real interval = right_position_f - left_position_f;
 
   Molecule molecule;
 
-  SCM line_thickness_scm = me->get_grob_property ("line-thickness");
+  SCM line_thickness_scm = me->get_grob_property ("thickness");
   Real line_thickness;
   if (gh_number_p (line_thickness_scm))
     {
@@ -201,9 +182,9 @@ Porrectus::brew_molecule (SCM smob)
       line_thickness = 1.0;
     }
   Real thickness =
-    line_thickness * me->paper_l ()->get_var ("stafflinethickness");
+    line_thickness * me->get_paper ()->get_var ("linethickness");
 
-  SCM porrectus_width_scm = me->get_grob_property ("porrectus-width");
+  SCM porrectus_width_scm = me->get_grob_property ("width");
   Real porrectus_width;
   if (gh_number_p (porrectus_width_scm))
     {
@@ -215,11 +196,11 @@ Porrectus::brew_molecule (SCM smob)
     }
   Real width = porrectus_width * Staff_symbol_referencer::staff_space (me);
 
-  if (String::compare_i (style, "vaticana") == 0)
+  if (String::compare (style, "vaticana") == 0)
     molecule = brew_vaticana_molecule (me, interval,
                                       solid, width, thickness,
                                       add_stem, stem_direction);
-  else if (String::compare_i (style, "mensural") == 0)
+  else if (String::compare (style, "mensural") == 0)
     molecule = brew_mensural_molecule (me, interval,
                                       solid, width, thickness,
                                       add_stem, stem_direction);
@@ -233,15 +214,25 @@ Porrectus::brew_molecule (SCM smob)
 
   molecule.translate_axis (left_position_f * space/2, Y_AXIS);
 
-  Molecule left_head_streepjes =
-    create_streepjes (me, (int)rint (left_position_f), interspaces, extent);
-  left_head_streepjes.translate_axis (left_position_f * space/2, Y_AXIS);
-  molecule.add_molecule (left_head_streepjes);
+  int left_pos = (int)rint (left_position_f);
+  if (abs (left_pos) - interspaces > 1)
+    {
+      Molecule left_head_ledger_lines =
+       Note_head::brew_ledger_lines (me, left_pos, interspaces, extent, true);
+      left_head_ledger_lines.translate_axis (left_position_f * space/2,
+                                            Y_AXIS);
+      molecule.add_molecule (left_head_ledger_lines);
+    }
 
-  Molecule right_head_streepjes =
-    create_streepjes (me, (int)rint (right_position_f), interspaces, extent);
-  right_head_streepjes.translate_axis (right_position_f * space/2, Y_AXIS);
-  molecule.add_molecule (right_head_streepjes);
+  int right_pos = (int)rint (right_position_f);
+  if (abs (right_pos) - interspaces > 1)
+    {
+      Molecule right_head_ledger_lines =
+       Note_head::brew_ledger_lines (me, right_pos, interspaces, extent, true);
+      right_head_ledger_lines.translate_axis (right_position_f * space/2,
+                                             Y_AXIS);
+      molecule.add_molecule (right_head_ledger_lines);
+    }
 
   return molecule.smobbed_copy();
 }
@@ -255,27 +246,32 @@ Porrectus::brew_vaticana_molecule (Item *me,
                                   bool add_stem,
                                   Direction stem_direction)
 {
-  Real space = Staff_symbol_referencer::staff_space (me);
-  Molecule molecule = Molecule ();
-
   if (interval >= 0.0)
     {
-      warning (_ ("ascending vaticana style porrectus"));
+      me->warning (_ ("ascending vaticana style porrectus"));
     }
 
+  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)
     {
       bool consider_interval =
        stem_direction * interval > 0.0;
 
-      Interval stem_box_x (-thickness/2, +thickness/2);
+      Interval stem_box_x (0, thickness);
       Interval stem_box_y;
 
       if (consider_interval)
-        {
-         Real y_length = interval / 2.0;
-         if (y_length < 1.2 * space)
-           y_length = 1.2 * space;
+       {
+         Real y_length = max (abs(interval)/2.0*space +
+                              (right_height-left_height),
+                              1.2*space);
          stem_box_y = Interval (0, y_length);
        }
       else
@@ -283,8 +279,8 @@ Porrectus::brew_vaticana_molecule (Item *me,
 
       Real y_correction =
        (stem_direction == UP) ?
-       0.3 * space :
-       - 0.3 * space - stem_box_y.length();
+       +0.5*left_height :
+       -0.5*left_height - stem_box_y.length();
 
       Box stem_box (stem_box_x, stem_box_y);
       Molecule stem = Lookup::filledbox (stem_box);
@@ -292,36 +288,66 @@ Porrectus::brew_vaticana_molecule (Item *me,
       molecule.add_molecule(stem);
     }
 
-  Box vertical_edge (Interval (-thickness/2, +thickness/2),
-                    Interval (-4*thickness/2, +4*thickness/2));
-  Molecule left_edge = Lookup::filledbox (vertical_edge);
-  Molecule right_edge = Lookup::filledbox (vertical_edge);
-  right_edge.translate_axis (width, X_AXIS);
-  right_edge.translate_axis (interval / 2.0, Y_AXIS);
-  molecule.add_molecule(left_edge);
-  molecule.add_molecule(right_edge);
-
-  Bezier bezier;
-  bezier.control_[0] = Offset (0.00 * width, 0.0);
-  bezier.control_[1] = Offset (0.33 * width, interval / 2.0);
-  bezier.control_[2] = Offset (0.66 * width, interval / 2.0);
-  bezier.control_[3] = Offset (1.00 * width, interval / 2.0);
-
-  Molecule slice;
-  slice = Lookup::slur (bezier, 0.0, thickness);
-  slice.translate_axis (-3 * thickness/2, Y_AXIS);
-  molecule.add_molecule (slice);
+  // 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 vaticana style porrectus
+  Bezier curve;
+  curve.control_[0] = Offset (0.00 * width, 0.0);
+  curve.control_[1] = Offset (0.33 * width, corrected_interval / 2.0);
+  curve.control_[2] = Offset (0.66 * width, corrected_interval / 2.0);
+  curve.control_[3] = Offset (1.00 * width, corrected_interval / 2.0);
+
+  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);
+    }
+
   if (solid)
-    for (int i = -2; i < +2; i++)
-      {
-       slice = Lookup::slur (bezier, 0.0, thickness);
-       slice.translate_axis (i * thickness/2, Y_AXIS);
-       molecule.add_molecule (slice);
-      }
-  slice = Lookup::slur (bezier, 0.0, thickness);
-  slice.translate_axis (+3 * thickness/2, Y_AXIS);
-  molecule.add_molecule (slice);
+    {
+      Molecule solid_head =
+       Lookup::bezier_sandwich (top_curve, bottom_curve);
+      molecule.add_molecule (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);
 
+      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 porrectus 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);
+      right_edge.translate_axis (width, X_AXIS);
+      right_edge.translate_axis (corrected_interval / 2.0, Y_AXIS);
+      molecule.add_molecule(right_edge);
+    }
+  molecule.translate_axis (ypos_correction, Y_AXIS);
   return molecule;
 }
 
@@ -335,13 +361,11 @@ Porrectus::brew_mensural_molecule (Item *me,
                                   Direction stem_direction)
 {
   Real space = Staff_symbol_referencer::staff_space (me);
+  Real height = 0.6 * space;
   Molecule molecule = Molecule ();
 
   if (add_stem)
     {
-      // Uugh.  This is currently the same as in
-      // brew_vaticana_molecule, but may eventually be changed.
-
       bool consider_interval =
        stem_direction * interval > 0.0;
 
@@ -350,9 +374,7 @@ Porrectus::brew_mensural_molecule (Item *me,
 
       if (consider_interval)
         {
-         Real y_length = interval / 2.0;
-         if (y_length < 1.2 * space)
-           y_length = 1.2 * space;
+         Real y_length = max (interval/2.0*space, 1.2*space);
          stem_box_y = Interval (0, y_length);
        }
       else
@@ -360,8 +382,8 @@ Porrectus::brew_mensural_molecule (Item *me,
 
       Real y_correction =
        (stem_direction == UP) ?
-       0.3 * space :
-       - 0.3 * space - stem_box_y.length();
+       +0.5*height :
+       -0.5*height - stem_box_y.length();
 
       Box stem_box (stem_box_x, stem_box_y);
       Molecule stem = Lookup::filledbox (stem_box);
@@ -369,7 +391,7 @@ Porrectus::brew_mensural_molecule (Item *me,
       molecule.add_molecule(stem);
     }
 
-  Real slope = (interval / 2.0) / width;
+  Real slope = (interval / 2.0 * space) / width;
 
   // Compensate optical illusion regarding vertical position of left
   // and right endings due to slope.
@@ -380,62 +402,36 @@ Porrectus::brew_mensural_molecule (Item *me,
   if (solid)
     {
       Molecule solid_head =
-       brew_horizontal_slope (width, corrected_slope, 0.6*space);
+       Lookup::horizontal_slope (width, corrected_slope, height);
       molecule.add_molecule (solid_head);
     }
-  else
+  else // outline
     {
       Molecule left_edge =
-         brew_horizontal_slope (thickness, corrected_slope, 0.6*space);
+       Lookup::horizontal_slope (thickness, corrected_slope, height);
       molecule.add_molecule(left_edge);
 
       Molecule right_edge =
-         brew_horizontal_slope (thickness, corrected_slope, 0.6*space);
+       Lookup::horizontal_slope (thickness, corrected_slope, height);
       right_edge.translate_axis (width-thickness, X_AXIS);
       right_edge.translate_axis (corrected_slope * (width-thickness), Y_AXIS);
       molecule.add_molecule(right_edge);
 
       Molecule bottom_edge =
-         brew_horizontal_slope (width, corrected_slope, thickness);
-      bottom_edge.translate_axis (-0.3*space, Y_AXIS);
+       Lookup::horizontal_slope (width, corrected_slope, thickness);
+      bottom_edge.translate_axis (-0.5*height, Y_AXIS);
       molecule.add_molecule (bottom_edge);
 
       Molecule top_edge =
-         brew_horizontal_slope (width, corrected_slope, thickness);
-      top_edge.translate_axis (+0.3*space, Y_AXIS);
+       Lookup::horizontal_slope (width, corrected_slope, thickness);
+      top_edge.translate_axis (+0.5*height, Y_AXIS);
       molecule.add_molecule (top_edge);
     }
   molecule.translate_axis (ypos_correction, Y_AXIS);
   return molecule;
 }
 
-/*
- * Horizontal Slope:
- *
- *            /|   ^
- *           / |   |
- *          /  |   | thickness
- *         /   |   |
- *        /    |   v
- *       |    /
- *       |   /
- * (0,0) x  /slope=dy/dx
- *       | /
- *       |/
- *
- *       <----->
- *        width
- */
-Molecule
-Porrectus::brew_horizontal_slope(Real width, Real slope, Real thickness)
-{
-  SCM width_scm = gh_double2scm (width);
-  SCM slope_scm = gh_double2scm (slope);
-  SCM thickness_scm = gh_double2scm (thickness);
-  SCM horizontal_slope = scm_list_n (ly_symbol2scm ("beam"),
-                                 width_scm, slope_scm,
-                                 thickness_scm, SCM_UNDEFINED);
-  Box b (Interval (0, width),
-        Interval (-thickness/2, thickness/2 + width*slope));
-  return Molecule (b, horizontal_slope);
-}
+
+ADD_INTERFACE (Porrectus,"porrectus-interface",
+  "A porrectus ligature, joining two note heads into a single grob.",
+  "left-head right-head width add-stem auto-properties solid direction");