]> git.donarmstrong.com Git - lilypond.git/blobdiff - lily/ledger-line-spanner.cc
*** empty log message ***
[lilypond.git] / lily / ledger-line-spanner.cc
index 76b5eb4dd3039fd835c49671a0e3228e4a29dd07..53da1d9463cd4219c36270a592edf2078c8cef88 100644 (file)
@@ -7,7 +7,6 @@
 */
 
 #include <map>
-#include <set>
 
 #include "item.hh"
 #include "note-head.hh"
@@ -49,8 +48,8 @@ Ledger_line_spanner::brew_ledger_lines (Grob *staff,
     {
       Real blotdiameter = ledgerlinethickness;
       Interval y_extent
-       = Interval (-0.5* (ledgerlinethickness),
-                   +0.5* (ledgerlinethickness));
+       = Interval (-0.5 * (ledgerlinethickness),
+                   +0.5 * (ledgerlinethickness));
       Stencil proto_ledger_line
        = Lookup::round_filled_box (Box (x_extent, y_extent), blotdiameter);
 
@@ -77,8 +76,38 @@ Ledger_line_spanner::brew_ledger_lines (Grob *staff,
   return stencil;
 }
 
-typedef std::map < int, Drul_array<Interval> > Head_extents_map;
-typedef std::map < int, Grob *> Column_map;
+static void
+set_rods (Drul_array<Interval> const &current_extents,
+         Drul_array<Interval> const &previous_extents,
+         Item *current_column,
+         Item *previous_column,
+         Real min_length_fraction)
+{
+  Direction d = UP;
+  do
+    {
+      if (!current_extents[d].is_empty ()
+         && !previous_extents[d].is_empty ())
+       {
+         Real total_head_length = previous_extents[d].length ()
+           + current_extents[d].length ();
+
+         Rod rod;
+         rod.distance_ = total_head_length
+           * (3 / 2 * min_length_fraction)
+           /*
+             we go from right to left.
+           */
+           - previous_extents[d][LEFT]
+           + current_extents[d][RIGHT];
+
+         rod.item_drul_[LEFT] = current_column;
+         rod.item_drul_[RIGHT] = previous_column;
+         rod.add_to_cols ();
+       }
+    }
+  while (flip (&d) != DOWN);
+}
 
 MAKE_SCHEME_CALLBACK (Ledger_line_spanner, set_spacing_rods, 1);
 SCM
@@ -91,81 +120,57 @@ Ledger_line_spanner::set_spacing_rods (SCM smob)
   if (!staff)
     return SCM_EOL;
 
-  Link_array<Grob> heads (extract_grob_array (me, ly_symbol2scm ("note-heads")));
-
-  if (heads.is_empty ())
-    return SCM_EOL;
+  SCM heads = me->get_property ("note-heads");
 
   Real min_length_fraction
     = robust_scm2double (me->get_property ("minimum-length-fraction"), 0.15);
 
-  Head_extents_map head_extents;
-  Column_map columns;
+  Drul_array<Interval> current_extents;
+  Drul_array<Interval> previous_extents;
+  Item *previous_column = 0;
+  Item *current_column = 0;
 
+  /*
+    Run through heads using a loop. Since Legder_line_spanner can
+    contain a lot of noteheads, superlinear performance is too slow.
+  */
   int interspaces = Staff_symbol::line_count (staff) - 1;
-  for (int i = heads.size (); i--;)
+  for (SCM hp = heads; scm_is_pair (hp); hp = scm_cdr (hp))
     {
-      Item *h = dynamic_cast<Item *> (heads[i]);
+      Item *h = dynamic_cast<Item *> (unsmob_grob (scm_car (hp)));
 
       int pos = Staff_symbol_referencer::get_rounded_position (h);
-      if (pos
-         && abs (pos) > interspaces)
-       {
-         Grob *column = h->get_column ();
-         int rank = Paper_column::get_rank (column);
-
-         Interval head_extent = h->extent (column, X_AXIS);
-         Direction vdir = Direction (sign (pos));
-         if (!vdir)
-           continue;
+      if (abs (pos) <= interspaces)
+       continue;
 
-         Interval prev_extent;
+      Item *column = h->get_column ();
+      if (current_column != column)
+       {
+         set_rods (current_extents, previous_extents,
+                   current_column, previous_column,
+                   min_length_fraction);
 
-         Head_extents_map::iterator j = head_extents.find (rank);
-         if (j != head_extents.end ())
-           prev_extent = (*j).second[vdir];
-         else
-           columns[rank] = column;
+         previous_column = current_column;
+         current_column = column;
+         previous_extents = current_extents;
 
-         prev_extent.unite (head_extent);
-         head_extents[rank][vdir] = prev_extent;
+         current_extents[DOWN].set_empty ();
+         current_extents[UP].set_empty ();
        }
-    }
-
-  for (Column_map::const_iterator c (columns.begin ()); c != columns.end (); c++)
-    {
-      Grob *column = (*c).second;
-      int rank = (*c).first;
-
-      int next_rank = rank + 2;
-
-      if (head_extents.find (next_rank) != head_extents.end ())
-       {
-         Drul_array<Interval> extents_left = head_extents[rank];
-         Drul_array<Interval> extents_right = head_extents[next_rank];
 
-         Direction d = DOWN;
-         do
-           {
-             if (!extents_left[d].is_empty () && !extents_right[d].is_empty ())
-               {
-                 Real l1 = extents_right[d].length () * min_length_fraction;
-                 Real l2 = extents_left[d].length () * min_length_fraction;
+      Interval head_extent = h->extent (column, X_AXIS);
+      Direction vdir = Direction (sign (pos));
+      if (!vdir)
+       continue;
 
-                 Rod rod;
-                 rod.distance_ = l1 + l2 + (l1+ l2) / 2.0
-                   + extents_left[d][RIGHT]
-                   - extents_right[d][LEFT];
-
-                 rod.item_drul_[LEFT] = dynamic_cast<Item *> (column);
-                 rod.item_drul_[RIGHT] = dynamic_cast<Item *> (columns[next_rank]);
-                 rod.add_to_cols ();
-               }
-           }
-         while (flip (&d) != DOWN);
-       }
+      current_extents[vdir].unite (head_extent);
     }
 
+  if (previous_column && current_column)
+    set_rods (current_extents, previous_extents,
+             current_column, previous_column,
+             min_length_fraction);
+
   return SCM_UNSPECIFIED;
 }
 
@@ -186,8 +191,8 @@ struct Ledger_request
 typedef std::map < int, Drul_array<Ledger_request> > Ledger_requests;
 
 /*
-  TODO: ledger share a lot of info. Lots of room to optimize away common
-  use of objects/variables.
+  TODO: ledger share a lot of info. Lots of room to optimize away
+  common use of objects/variables.
 */
 MAKE_SCHEME_CALLBACK (Ledger_line_spanner, print, 1);
 SCM
@@ -241,7 +246,7 @@ Ledger_line_spanner::print (SCM smob)
          reqs[rank][vdir].ledger_extent_.unite (ledger_extent);
          reqs[rank][vdir].head_extent_.unite (head_extent);
          reqs[rank][vdir].position_
-           = vdir * ((vdir* reqs[rank][vdir].position_) >? (vdir *pos));
+           = vdir * ((vdir * reqs[rank][vdir].position_) >? (vdir * pos));
        }
     }
 
@@ -269,14 +274,14 @@ Ledger_line_spanner::print (SCM smob)
              Direction which = LEFT;
              do
                {
-                 Ledger_request &lr = ((which == LEFT) ? *last : *i).second[d];
+                 Ledger_request &lr = ((which == LEFT) ? * last : *i).second[d];
 
                  // due tilt of quarter note-heads
                  bool both
                    = (abs (last->second[d].position_) > interspaces + 1
                       && abs (i->second[d].position_) > interspaces + 1);
 
-                 Real limit = (center + (both? which * gap / 2 : 0));
+                 Real limit = (center + (both ? which * gap / 2 : 0));
                  lr.ledger_extent_.elem_ref (-which)
                    = which * (which * lr.ledger_extent_[-which] >? which * limit);
                }
@@ -299,7 +304,7 @@ Ledger_line_spanner::print (SCM smob)
        {
          Interval head_size = h->extent (common[X_AXIS], X_AXIS);
          Interval ledger_size = head_size;
-         ledger_size.widen (ledger_size.length ()* length_fraction);
+         ledger_size.widen (ledger_size.length () * length_fraction);
 
          Interval max_size = reqs[Paper_column::get_rank (h->get_column ())][Direction (sign (pos))].ledger_extent_;
 
@@ -319,7 +324,6 @@ Ledger_line_spanner::print (SCM smob)
                TODO: shorten 2 ledger lines for the case natural +
                downstem.
              */
-
            }
 
          ledgers.add_stencil (brew_ledger_lines (staff, pos, interspaces,