]> git.donarmstrong.com Git - lilypond.git/commitdiff
Makes all side-positioning based on skylines instead of boxes.
authorMike Solomon <mike@apollinemike.com>
Thu, 10 Jan 2013 07:54:12 +0000 (08:54 +0100)
committerMike Solomon <mike@apollinemike.com>
Thu, 10 Jan 2013 07:54:12 +0000 (08:54 +0100)
The major work is in side-position-interface.cc, with minor
modifications at several places in the code-base to adapt to this.

This allows for snugger positioning of horizontally-oriented
fingerings.

A side-effect of this patch is that side-positioning of all
cross-staff grobs delves into the element list of axis-groups
in order to better guess position, which results in less
collisions (for example, dynamics are less likely to collide
with cross-staff beams).

37 files changed:
input/regression/add-stem-support.ly [new file with mode: 0644]
input/regression/dynamics-avoid-cross-staff-stem.ly
input/regression/finger-chords.ly
input/regression/fingering-column.ly
input/regression/les-nereides.ly
lily/axis-group-interface.cc
lily/box-quarantine.cc [new file with mode: 0644]
lily/box.cc
lily/drum-note-engraver.cc
lily/dynamic-align-engraver.cc
lily/fingering-column-engraver.cc
lily/fingering-column.cc
lily/fingering-engraver.cc
lily/grob-property.cc
lily/grob.cc
lily/include/axis-group-interface.hh
lily/include/box-quarantine.hh [new file with mode: 0644]
lily/include/box.hh
lily/include/grob.hh
lily/include/multi-measure-rest.hh
lily/include/self-alignment-interface.hh
lily/include/side-position-interface.hh
lily/include/skyline.hh
lily/interval-minefield.cc
lily/multi-measure-rest.cc
lily/new-dynamic-engraver.cc
lily/new-fingering-engraver.cc
lily/pointer-group-interface.cc
lily/script-column.cc
lily/self-alignment-interface.cc
lily/side-position-interface.cc
lily/skyline.cc
lily/stencil-integral.cc
scm/define-grob-properties.scm
scm/define-grobs.scm
scm/lily-library.scm
scm/output-lib.scm

diff --git a/input/regression/add-stem-support.ly b/input/regression/add-stem-support.ly
new file mode 100644 (file)
index 0000000..ab22af6
--- /dev/null
@@ -0,0 +1,25 @@
+\version "2.17.10"
+
+\header {
+  texidoc = "@code{add-stem-support} can be removed or implemented
+only for beamed notes.
+"
+}
+
+music = {
+  \clef bass
+  \stemUp
+  <g^3 a^5>2..->
+  r16 eeses'16
+  \set fingeringOrientations = #'(right)
+  <c e>8-1-4 <c^1 e^4> <g,-3 b,-4> r
+  r2
+}
+
+{
+  \music
+  \override Fingering #'add-stem-support = ##f
+  \music
+  \override Fingering #'add-stem-support = #only-if-beamed
+  \music
+}
\ No newline at end of file
index e0f4a738bed9e46a0fc4f35f440e37d057cada44..078d876ad78ec32ab59ad653f07645ee3fe77c9e 100644 (file)
@@ -1,16 +1,19 @@
-\version "2.16.0"
+\version "2.17.10"
 
 \header {
-  texidoc = "LilyPond automatically shifts dynamics that collide with
-cross-staff stems when manual beams are used."
+  texidoc = "Dynamics are correctly nested over/under cross staff stems.
+They are, however, not yet factored into horizontal spacing - the fff
+collides with other grobs.
+"
 }
 
 \new GrandStaff <<
   \new Staff = "PnRH" {
     \relative g {
       \stemDown gis8 \p [ \change Staff = "PnLH" \stemUp a, \fff ]
+      a8 \p [ \change Staff = "PnRH" \stemDown gis'8 \fff ]
       \change Staff = "PnRH" r4
     }
   }
-  \new Staff = "PnLH" { \clef "F" { s4 r4 } }
+  \new Staff = "PnLH" { \clef "F" { s2 r4 } }
 >>
index 488245c2e6e85a37de94aa3eca457f59a05af5ae..2c5c6b6972179842c172338accbf017cbfb3e4f2 100644 (file)
@@ -1,11 +1,11 @@
 
-\version "2.17.6"
+\version "2.17.10"
 \header {
 
   texidoc = "It is possible to associate
 fingerings uniquely with notes. This makes it possible to add
-horizontal fingerings to notes. Fingering clears stems and flags
-if @code{'add-stem-support} is set.
+horizontal fingerings to notes. Fingering defaults to not clearing
+flags and stems unless there is a collision or a beam.
 "
 
 }
index ccf0aafaa0b894ad85c5ee0bf4d6e28352554712..d4d2551b2e4a74c97ff79c55a7dc2123ef1578fb 100644 (file)
@@ -1,8 +1,9 @@
-\version "2.17.6"
+\version "2.17.10"
 
 \header {
   texidoc = "Horizontal @code{Fingering} grobs that collide do not intersect.
-Non-intersecting @code{Fingering} grobs are left alone.
+Non-intersecting @code{Fingering} grobs are left alone. This is managed
+by the @code{FingeringColumn} grob.
 "
 }
 
index c8c47c4bb984abe1ed898813f1fc4b715a5a818a..c87772419dd455a914c337282834c897bbabd9d4 100644 (file)
@@ -1,4 +1,4 @@
-\version "2.17.6"
+\version "2.17.10"
 
 \header {
     composer = "ARTHUR GRAY"
@@ -17,7 +17,7 @@ Nastiest piece of competition at
 http://www.orphee.com/comparison/study.html, see
 http://www.orphee.com/comparison/gray.pdf
 
-Lines that contain tweaks (10 currently, not counting reverts) are
+Lines that contain tweaks (3 currently, not counting reverts) are
 marked with %tweak
 
 possibly more impressive to render without tweaks?
@@ -98,10 +98,6 @@ trebleTwo = \new Voice \relative c''{
     <e, gis, e d!>2
     | %5
     s8 cis4. d4
-    % fair to count as one tweak?
-    \override Fingering.add-stem-support = ##t %tweak
-    \override Fingering.padding = #0.15
-    \override Fingering.slur-padding = #0.1
     <cis e,>8[( <d,_3 b'_1>
     | %6
     <cis_1 a'_2>)] cis'4. d4
index 707e045c9b1a13b3127997d8c1ec05fed81467b7..1ed1f7f8fcc109e3d65ea2ed83d556b3b936f217 100644 (file)
@@ -51,6 +51,19 @@ Axis_group_interface::get_default_outside_staff_padding ()
   return default_outside_staff_padding_;
 }
 
+MAKE_SCHEME_CALLBACK (Axis_group_interface, cross_staff, 1);
+SCM
+Axis_group_interface::cross_staff (SCM smob)
+{
+  Grob *me = unsmob_grob (smob);
+  extract_grob_set (me, "elements", elts);
+  for (vsize i = 0; i < elts.size (); i++)
+    if (to_boolean (elts[i]->get_property ("cross-staff")))
+      return SCM_BOOL_T;
+
+  return SCM_BOOL_F;
+}
+
 void
 Axis_group_interface::add_element (Grob *me, Grob *e)
 {
@@ -99,7 +112,8 @@ Axis_group_interface::relative_maybe_bound_group_extent (vector<Grob *> const &e
   for (vsize i = 0; i < elts.size (); i++)
     {
       Grob *se = elts[i];
-      if (!to_boolean (se->get_property ("cross-staff")))
+      if (has_interface (se)
+          || !to_boolean (se->get_property ("cross-staff")))
         {
           Interval dims = (bound && has_interface (se)
                            ? generic_bound_extent (se, common, a)
@@ -240,7 +254,8 @@ Axis_group_interface::adjacent_pure_heights (SCM smob)
     {
       Grob *g = elts[i];
 
-      if (to_boolean (g->get_property ("cross-staff")))
+      if (to_boolean (g->get_property ("cross-staff"))
+          && !has_interface (g))
         continue;
 
       bool outside_staff = scm_is_number (g->get_property ("outside-staff-priority"));
@@ -392,9 +407,7 @@ SCM
 Axis_group_interface::calc_skylines (SCM smob)
 {
   Grob *me = unsmob_grob (smob);
-  extract_grob_set (me, Grob_array::unsmob (me->get_object ("vertical-skyline-elements")) ? "vertical-skyline-elements" : "elements", elts);
-  Skyline_pair skylines = skyline_spacing (me, elts);
-
+  Skyline_pair skylines = skyline_spacing (me);
   return skylines.smobbed_copy ();
 }
 
@@ -435,11 +448,13 @@ Axis_group_interface::combine_skylines (SCM smob)
 SCM
 Axis_group_interface::generic_group_extent (Grob *me, Axis a)
 {
+  extract_grob_set (me, "elements", elts);
+
   /* trigger the callback to do skyline-spacing on the children */
   if (a == Y_AXIS)
-    (void) me->get_property ("vertical-skylines");
+    for (vsize i = 0; i < elts.size (); i++)
+      (void) elts[i]->get_property ("vertical-skylines");
 
-  extract_grob_set (me, "elements", elts);
   Grob *common = common_refpoint_of_array (elts, me, a);
 
   Real my_coord = me->relative_coordinate (common, a);
@@ -834,8 +849,10 @@ Axis_group_interface::outside_staff_ancestor (Grob *me)
 // that there is no room for the cross-staff grob. It also means, of course, that
 // we don't get the benefits of skyline placement for cross-staff grobs.
 Skyline_pair
-Axis_group_interface::skyline_spacing (Grob *me, vector<Grob *> elements)
+Axis_group_interface::skyline_spacing (Grob *me)
 {
+  extract_grob_set (me, Grob_array::unsmob (me->get_object ("vertical-skyline-elements")) ? "vertical-skyline-elements" : "elements", fakeelements);
+  vector<Grob *> elements (fakeelements);
   for (vsize i = 0; i < elements.size (); i++)
     /*
       As a sanity check, we make sure that no grob with an outside staff priority
@@ -870,12 +887,13 @@ Axis_group_interface::skyline_spacing (Grob *me, vector<Grob *> elements)
 
   vsize i = 0;
   vector<Skyline_pair> inside_staff_skylines;
+
   for (i = 0; i < elements.size ()
        && !scm_is_number (elements[i]->get_property ("outside-staff-priority")); i++)
     {
       Grob *elt = elements[i];
       Grob *ancestor = outside_staff_ancestor (elt);
-      if (!(to_boolean (elt->get_property ("cross-staff")) || ancestor))
+      if (!ancestor)
         add_interior_skylines (elt, x_common, y_common, &inside_staff_skylines);
       if (ancestor)
         riders.insert (pair<Grob *, Grob *> (ancestor, elt));
diff --git a/lily/box-quarantine.cc b/lily/box-quarantine.cc
new file mode 100644 (file)
index 0000000..dff8587
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+  This file is part of LilyPond, the GNU music typesetter.
+
+  Copyright (C) 2011--2012 Mike Solomon <mike@mikesolomon.org>
+  Jan Nieuwenhuizen <janneke@gnu.org>
+
+  LilyPond is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  LilyPond is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "box-quarantine.hh"
+#include <functional>
+
+Box_quarantine::Box_quarantine (Real padding, Axis a)
+  : padding_ (padding), a_ (a)
+{
+}
+
+void
+Box_quarantine::add_box_to_quarantine (Box infected)
+{
+  Box nbox (infected);
+  nbox[a_].widen (padding_ / 2);
+  boxes_to_quarantine_.push_back (nbox);
+}
+
+vector<Box>
+Box_quarantine::quarantined_boxes ()
+{
+  return boxes_to_quarantine_;
+}
+
+struct Intersection_info
+{
+  vsize index_;
+  Real amount_;
+  int mid_;
+  Intersection_info (vsize index, Real amount, int mid);
+};
+
+Intersection_info::Intersection_info (vsize index, Real amount, int mid)
+  : index_ (index), amount_ (amount), mid_ (mid)
+{
+}
+
+/*
+  boxes_to_quarantine_ contains a vector of boxes that may
+  or may not overlap.  it iterates through these boxes,
+  pushing quarantined_boxes_ epsilon over or epsilon under a
+  collision.  when this type of change happens, the loop is marked
+  as "dirty" and re-iterated.
+
+  TODO: not sure if this loop causes infinite behavior...
+*/
+
+bool
+sort_towards_middle(Intersection_info ii0, Intersection_info ii1)
+{
+  // ugh...with C++11, we'll just be able to do a factory instead of
+  // bundling mid with the Intersection_info
+  int mid = ii0.mid_;
+  assert ((double)(ii0.index_ - mid) >= 0.0);
+  assert ((double)(ii1.index_ - mid) >= 0.0);
+  return fabs (ii0.index_ - mid) < fabs (ii1.index_ - mid);
+}
+
+void
+Box_quarantine::solve ()
+{
+  int mid = boxes_to_quarantine_.size () / 2;
+  Real epsilon = 1.0e-4;
+  bool dirty = false;
+  do
+    {
+      dirty = false;
+      vector<Intersection_info> ii;
+      for (vsize i = 0; i < boxes_to_quarantine_.size () - 1; i++)
+        {
+          Box scratch (boxes_to_quarantine_[i]);
+          scratch.intersect (boxes_to_quarantine_[i + 1]);
+          if (!scratch.is_empty ())
+            ii.push_back (Intersection_info (i, scratch[a_].length (), mid));
+        }
+      vector_sort (ii, sort_towards_middle);
+      if (ii.size () > 0)
+        {
+          Offset shift (-(epsilon + ii[0].amount_ / 2.0), 0.0);
+          if (a_ == Y_AXIS)
+            shift = shift.swapped ();
+          boxes_to_quarantine_[ii[0].index_].translate (shift);
+          shift[a_] = -shift[a_];
+          boxes_to_quarantine_[ii[0].index_ + 1].translate (shift);
+          dirty = true;
+        }
+    }
+  while (dirty);
+}
index 52af33a142362dc26bcf3f9c94727d7e930d1f3c..bc0a975ed0d3d91b0be837f5810af3fb8b991795 100644 (file)
@@ -51,6 +51,13 @@ Box::set_empty ()
   interval_a_[Y_AXIS].set_empty ();
 }
 
+bool
+Box::is_empty () const
+{
+  return interval_a_[X_AXIS].is_empty ()
+         || interval_a_[Y_AXIS].is_empty ();
+}
+
 Box::Box (Interval ix, Interval iy)
 {
   x () = ix;
@@ -97,6 +104,13 @@ Box::widen (Real x, Real y)
   interval_a_[Y_AXIS].widen (y);
 }
 
+void
+Box::intersect (Box b)
+{
+  interval_a_[X_AXIS].intersect (b[X_AXIS]);
+  interval_a_[Y_AXIS].intersect (b[Y_AXIS]);
+}
+
 // for debugging
 
 void
index 251d2099fe52ae5eee7c4938a44cbd42136bb070..06d24fdea60343494a7aaa7005d5f70aa6654fc6 100644 (file)
@@ -128,6 +128,8 @@ Drum_notes_engraver::acknowledge_note_column (Grob_info inf)
       if (!e->get_parent (X_AXIS)
           && Side_position_interface::get_axis (e) == Y_AXIS)
         e->set_parent (inf.grob (), X_AXIS);
+
+      Side_position_interface::add_support (e, inf.grob ());
     }
 }
 
index 265498658abb01358aa6cd86b18ee21986fa666b..37f93cd5c4dce99bae0716661f99beee03440d9c 100644 (file)
@@ -34,7 +34,8 @@
 class Dynamic_align_engraver : public Engraver
 {
   TRANSLATOR_DECLARATIONS (Dynamic_align_engraver);
-  DECLARE_ACKNOWLEDGER (note_column);
+  DECLARE_ACKNOWLEDGER (rhythmic_head);
+  DECLARE_ACKNOWLEDGER (stem);
   DECLARE_ACKNOWLEDGER (dynamic);
   DECLARE_ACKNOWLEDGER (footnote_spanner);
   DECLARE_END_ACKNOWLEDGER (dynamic);
@@ -64,7 +65,8 @@ Dynamic_align_engraver::Dynamic_align_engraver ()
 }
 
 ADD_ACKNOWLEDGER (Dynamic_align_engraver, dynamic);
-ADD_ACKNOWLEDGER (Dynamic_align_engraver, note_column);
+ADD_ACKNOWLEDGER (Dynamic_align_engraver, rhythmic_head);
+ADD_ACKNOWLEDGER (Dynamic_align_engraver, stem);
 ADD_ACKNOWLEDGER (Dynamic_align_engraver, footnote_spanner);
 ADD_END_ACKNOWLEDGER (Dynamic_align_engraver, dynamic);
 
@@ -107,7 +109,13 @@ Dynamic_align_engraver::acknowledge_footnote_spanner (Grob_info info)
 }
 
 void
-Dynamic_align_engraver::acknowledge_note_column (Grob_info info)
+Dynamic_align_engraver::acknowledge_rhythmic_head (Grob_info info)
+{
+  support_.push_back (info.grob ());
+}
+
+void
+Dynamic_align_engraver::acknowledge_stem (Grob_info info)
 {
   support_.push_back (info.grob ());
 }
index bff3d7c8861e4dd105fed0093a25f7a0c035ceb1..1c5b904809809c81f09022b68638edab7c39637d 100644 (file)
@@ -27,7 +27,7 @@
 
 /**
    Find potentially colliding scripts, and put them in a
-   Fingering_column, that will fix the collisions.  */
+   Fingering_column, that will fix the columns.  */
 class Fingering_column_engraver : public Engraver
 {
   Drul_array<Grob *> fingering_columns_;
index d027dfa754acab6f586dda014b3c51513cda7f8a..76c7bd3b89bd884b782fbdcefb0568bdf8aac41f 100644 (file)
@@ -19,6 +19,7 @@
 
 #include "grob.hh"
 #include "fingering-column.hh"
+#include "box-quarantine.hh"
 #include "pointer-group-interface.hh"
 #include "staff-symbol-referencer.hh"
 #include "item.hh"
 
 #include <map>
 
+// The sorting algorithm may not preserve the order of the
+// original fingerings. We use Fingering_position_info to retain
+// this order.
+
+struct Fingering_position_info {
+  Box box_;
+  vsize idx_;
+  Fingering_position_info (Box, vsize);
+};
+
+Fingering_position_info::Fingering_position_info (Box box, vsize idx)
+  : box_ (box), idx_ (idx)
+{
+}
+
+bool
+fingering_position_less (Fingering_position_info fpi0, Fingering_position_info fpi1)
+{
+  return Interval::left_less (fpi0.box_[Y_AXIS], fpi1.box_[Y_AXIS]);
+}
+
 MAKE_SCHEME_CALLBACK (Fingering_column, calc_positioning_done, 1);
 SCM
 Fingering_column::calc_positioning_done (SCM smob)
 {
   Grob *me = unsmob_grob (smob);
-  Real padding = robust_scm2double (me->get_property ("padding"), 0.0);
   if (!me->is_live ())
     return SCM_BOOL_T;
 
   map<Grob *, bool> shifted;
 
-  Real ss = Staff_symbol_referencer::staff_space (me);
-
   me->set_property ("positioning-done", SCM_BOOL_T);
 
   extract_grob_set (me, "fingerings", const_fingerings);
@@ -49,63 +68,39 @@ Fingering_column::calc_positioning_done (SCM smob)
       return SCM_BOOL_T;
     }
 
-  // order the fingerings from bottom to top
   vector<Grob *> fingerings;
   for (vsize i = 0; i < const_fingerings.size (); i++)
     fingerings.push_back (const_fingerings[i]);
 
-  vector_sort (fingerings, pure_position_less);
 
   Grob *common[2] = {common_refpoint_of_array (fingerings, me, X_AXIS),
                      common_refpoint_of_array (fingerings, me, Y_AXIS)};
 
+  Real padding = robust_scm2double (me->get_property ("padding"), 0.2);
+  Box_quarantine bq (padding, Y_AXIS);
+  vector<Fingering_position_info> origs;
   for (vsize i = 0; i < fingerings.size (); i++)
-    fingerings[i]->translate_axis (-fingerings[i]->extent (common[Y_AXIS], Y_AXIS).length () / 2, Y_AXIS);
-
-  for (vsize i = min (fingerings.size () - 1, fingerings.size () / 2 + 1); i >= 1; i--)
-    for (vsize j = i; j--;)
-      {
-        Interval ex_i = fingerings[i]->extent (common[X_AXIS], X_AXIS);
-        Interval ex_j = fingerings[j]->extent (common[X_AXIS], X_AXIS);
-        Interval ey_i = fingerings[i]->extent (common[Y_AXIS], Y_AXIS);
-        Interval ey_j = fingerings[j]->extent (common[Y_AXIS], Y_AXIS);
-        Real tval = min (0.0, (ey_i[DOWN] - ey_j[UP] - padding) / 2);
-        if (tval != 0.0 && !intersection (ex_i, ex_j).is_empty ())
-          {
-            if (shifted[fingerings[i]] || shifted[fingerings[j]])
-              fingerings[j]->translate_axis (tval * 2, Y_AXIS);
-            else
-              {
-                fingerings[i]->translate_axis (-tval, Y_AXIS);
-                fingerings[j]->translate_axis (tval, Y_AXIS);
-              }
-            shifted[fingerings[i]] = true;
-            shifted[fingerings[j]] = true;
-          }
-      }
-
-  for (vsize i = fingerings.size () / 2 - 1; i < fingerings.size () - 1; i++)
-    for (vsize j = i + 1; j < fingerings.size (); j++)
-      {
-        Interval ex_i = fingerings[i]->extent (common[X_AXIS], X_AXIS);
-        Interval ex_j = fingerings[j]->extent (common[X_AXIS], X_AXIS);
-        Interval ey_i = fingerings[i]->extent (common[Y_AXIS], Y_AXIS);
-        Interval ey_j = fingerings[j]->extent (common[Y_AXIS], Y_AXIS);
-        Real tval = max (0.0, (ey_i[UP] - ey_j[DOWN] + padding) / 2);
-        if (tval != 0.0 && !intersection (ex_i, ex_j).is_empty ())
-          {
-            if (shifted[fingerings[i]] || shifted[fingerings[j]])
-              fingerings[j]->translate_axis (tval * 2, Y_AXIS);
-            else
-              {
-                fingerings[i]->translate_axis (-tval, Y_AXIS);
-                fingerings[j]->translate_axis (tval, Y_AXIS);
-              }
-            shifted[fingerings[i]] = true;
-            shifted[fingerings[j]] = true;
-          }
-      }
+    {
+      Interval x_ext = fingerings[i]->extent (common[X_AXIS], X_AXIS);
+      // center on Y parent
+      fingerings[i]->translate_axis (-fingerings[i]->extent (fingerings[i], Y_AXIS).length () / 2.0, Y_AXIS);
+      Interval y_ext = fingerings[i]->extent (fingerings[i], Y_AXIS)
+                       + fingerings[i]->get_parent (Y_AXIS)
+                         ->relative_coordinate (common[Y_AXIS], Y_AXIS);
+      origs.push_back(Fingering_position_info (Box (x_ext, y_ext), i));
+    }
+
+  // order the fingerings from bottom to top
+  vector_sort (origs, fingering_position_less);
+
+  for (vsize i = 0; i < origs.size (); i++)
+    bq.add_box_to_quarantine (Box (origs[i].box_));
+
+  bq.solve ();
+  vector<Box> news (bq.quarantined_boxes ());
 
+  for (vsize i = 0; i < origs.size (); i++)
+    fingerings[origs[i].idx_]->translate_axis (news[i][Y_AXIS][DOWN] - origs[i].box_[Y_AXIS][DOWN], Y_AXIS);
 
   return SCM_BOOL_T;
 }
index a364947b08eb363e02718616aab51a359d07136b..2571ac1d709c10bec1e00df16e873877aefdbd58 100644 (file)
@@ -41,6 +41,7 @@ protected:
   DECLARE_TRANSLATOR_LISTENER (fingering);
   DECLARE_ACKNOWLEDGER (rhythmic_head);
   DECLARE_ACKNOWLEDGER (stem);
+  DECLARE_ACKNOWLEDGER (flag);
 
 private:
   void make_script (Direction, Stream_event *, int);
@@ -60,6 +61,13 @@ Fingering_engraver::acknowledge_stem (Grob_info inf)
     Side_position_interface::add_support (fingerings_[i], inf.grob ());
 }
 
+void
+Fingering_engraver::acknowledge_flag (Grob_info inf)
+{
+  for (vsize i = 0; i < fingerings_.size (); i++)
+    Side_position_interface::add_support (fingerings_[i], inf.grob ());
+}
+
 void
 Fingering_engraver::acknowledge_rhythmic_head (Grob_info inf)
 {
@@ -139,6 +147,7 @@ Fingering_engraver::Fingering_engraver ()
 
 ADD_ACKNOWLEDGER (Fingering_engraver, rhythmic_head);
 ADD_ACKNOWLEDGER (Fingering_engraver, stem);
+ADD_ACKNOWLEDGER (Fingering_engraver, flag);
 
 ADD_TRANSLATOR (Fingering_engraver,
                 /* doc */
index 3afe182c0ef07793ecf1fd0d09a5ea147c9bd4e1..9120aefdf29939b5f16c6e60fb7218fdcafeba68 100644 (file)
@@ -170,7 +170,7 @@ Grob::internal_get_property (SCM sym) const
     {
       programming_error (to_string ("cyclic dependency: calculation-in-progress encountered for #'%s (%s)",
                                     ly_symbol2string (sym).c_str (),
-                                    name ().c_str ()));
+                                    name ().c_str ()));//assert (1==0);
       if (debug_property_callbacks)
         {
           message ("backtrace: ");
index 031af32636878b3a163bb0ea483bca2e0d0fcdc5..4c54cbc508a318938b50ef5258ce012ff2f381f2 100644 (file)
@@ -81,9 +81,9 @@ Grob::Grob (SCM basicprops)
   if (get_property_data ("Y-extent") == SCM_EOL)
     set_property ("Y-extent", Grob::stencil_height_proc);
   if (get_property_data ("vertical-skylines") == SCM_EOL)
-    set_property ("vertical-skylines", Grob::simple_vertical_skylines_from_stencil_proc);
+    set_property ("vertical-skylines", Grob::simple_vertical_skylines_from_extents_proc);
   if (get_property_data ("horizontal-skylines") == SCM_EOL)
-    set_property ("horizontal-skylines", Grob::simple_horizontal_skylines_from_stencil_proc);
+    set_property ("horizontal-skylines", Grob::simple_horizontal_skylines_from_extents_proc);
 }
 
 Grob::Grob (Grob const &s)
@@ -485,6 +485,9 @@ Interval
 Grob::pure_height (Grob *refp, int start, int end)
 {
   SCM iv_scm = get_pure_property ("Y-extent", start, end);
+  // TODO: Why is this Interval (0,0)
+  // Shouldn't it just be an empty interval?
+  // 0,0 puts an arbitrary point at 0,0 which will influence spacing
   Interval iv = robust_scm2interval (iv_scm, Interval (0, 0));
   Real offset = pure_relative_y_coordinate (refp, start, end);
 
index 4098a19514b6efe4f7c04f660d7cd6d06f6e0cfa..1ba26af829459cebb6ce4c632a4792a1bf421953 100644 (file)
@@ -34,6 +34,7 @@ class Axis_group_interface
   static Real get_default_outside_staff_padding ();
   static Interval generic_bound_extent (Grob *me, Grob *common, Axis a);
   static Interval pure_group_height (Grob *me, int start, int end);
+  DECLARE_SCHEME_CALLBACK (cross_staff, (SCM smob));
   DECLARE_SCHEME_CALLBACK (width, (SCM smob));
   DECLARE_SCHEME_CALLBACK (calc_x_common, (SCM smob));
   DECLARE_SCHEME_CALLBACK (calc_y_common, (SCM smob));
@@ -62,7 +63,7 @@ class Axis_group_interface
   static Interval part_of_line_pure_height (Grob *me, bool begin, int, int);
 
   static Grob *outside_staff_ancestor (Grob *me);
-  static Skyline_pair skyline_spacing (Grob *me, vector<Grob *> elements);
+  static Skyline_pair skyline_spacing (Grob *me);
   static void add_element (Grob *me, Grob *);
   static void set_axes (Grob *, Axis, Axis);
   static bool has_axis (Grob *, Axis);
diff --git a/lily/include/box-quarantine.hh b/lily/include/box-quarantine.hh
new file mode 100644 (file)
index 0000000..3673a95
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+  This file is part of LilyPond, the GNU music typesetter.
+
+  Copyright (C) 2012 Mike Solomon <mike@mikesolomon.org>
+
+  LilyPond is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  LilyPond is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef BOX_QUARANTINE_HH
+#define BOX_QUARANTINE_HH
+
+#include "lily-proto.hh"
+#include "std-vector.hh"
+#include "box.hh"
+
+class Box_quarantine
+{
+public:
+  Box_quarantine (Real, Axis);
+  void add_box_to_quarantine (Box);
+  void solve ();
+  vector<Box> quarantined_boxes ();
+
+private:
+  vector<Box> boxes_to_quarantine_;
+  Real padding_;
+  Axis a_;
+};
+
+#endif // BOX_QUARANTINE_HH
index ab0d3f5300b614211adf9c8f0a18a91f2e3e686c..63224f2f880debeb58567524dfb7dac51e1ae6a4 100644 (file)
@@ -21,6 +21,7 @@ public:
   Interval operator [] (Axis a) const;
   Interval &operator [] (Axis a);
   Real area () const;
+  bool is_empty () const;
 
   Offset center () const;
 
@@ -32,6 +33,7 @@ public:
   void widen (Real x, Real y);
   void scale (Real r);
   void unite (Box b);
+  void intersect (Box b);
   void print ();
   Box ();
   Box (Interval ix, Interval iy);
index 09cd566ad335b39708990d05ab74894ff2099af1..a98b19a9f6ea4098041e3468eeaf270f6762d758 100644 (file)
@@ -71,10 +71,12 @@ public:
   DECLARE_SCHEME_CALLBACK (y_parent_positioning, (SCM));
   DECLARE_SCHEME_CALLBACK (stencil_height, (SCM smob));
   DECLARE_SCHEME_CALLBACK (stencil_width, (SCM smob));
-  DECLARE_SCHEME_CALLBACK (simple_vertical_skylines_from_stencil, (SCM smob));
+  DECLARE_SCHEME_CALLBACK (pure_simple_vertical_skylines_from_extents, (SCM smob, SCM, SCM));
+  DECLARE_SCHEME_CALLBACK (simple_vertical_skylines_from_extents, (SCM smob));
   DECLARE_SCHEME_CALLBACK (vertical_skylines_from_stencil, (SCM smob));
   DECLARE_SCHEME_CALLBACK (vertical_skylines_from_element_stencils, (SCM smob));
-  DECLARE_SCHEME_CALLBACK (simple_horizontal_skylines_from_stencil, (SCM smob));
+  DECLARE_SCHEME_CALLBACK (pure_simple_horizontal_skylines_from_extents, (SCM smob, SCM, SCM));
+  DECLARE_SCHEME_CALLBACK (simple_horizontal_skylines_from_extents, (SCM smob));
   DECLARE_SCHEME_CALLBACK (horizontal_skylines_from_stencil, (SCM smob));
   DECLARE_SCHEME_CALLBACK (horizontal_skylines_from_element_stencils, (SCM smob));
 
@@ -161,7 +163,7 @@ public:
   virtual bool pure_is_visible (int start, int end) const;
   bool check_cross_staff (Grob *common);
   static bool less (Grob *g1, Grob *g2);
-  static SCM internal_simple_skylines_from_stencil (SCM, Axis);
+  static SCM maybe_pure_internal_simple_skylines_from_extents (Grob *, Axis, bool, int, int, bool, bool);
   static SCM internal_skylines_from_element_stencils (SCM, Axis);
 };
 
index 55943c4b4421afb29518a12eea85a4b86ed5424b..d012a77b0712ae052f1cb7ecfd3373c0c8cbabf9 100644 (file)
@@ -28,6 +28,7 @@ class Multi_measure_rest
 public:
   DECLARE_GROB_INTERFACE ();
   DECLARE_SCHEME_CALLBACK (print, (SCM));
+  DECLARE_SCHEME_CALLBACK (height, (SCM));
   DECLARE_SCHEME_CALLBACK (percent, (SCM));
   static void add_column (Grob *, Item *);
   DECLARE_SCHEME_CALLBACK (set_spacing_rods, (SCM));
index c3c7e9c878f2d3f999ded36dbc3de461d8a777e1..dd69f8663000e1a2aaf9d3e985451fbedce01b9e 100644 (file)
@@ -30,10 +30,8 @@ struct Self_alignment_interface
   static SCM aligned_on_self (Grob *me, Axis a, bool pure, int start, int end);
   static SCM centered_on_object (Grob *me, Axis a);
   static SCM aligned_on_parent (Grob *me, Axis a);
-  static SCM avoid_colliding_grobs (Grob *me, Axis a, Real offset);
   static void set_center_parent (Grob *me, Axis a);
   static void set_align_self (Grob *me, Axis a);
-  static void avoid_x_collisions (Grob *me);
 
   DECLARE_SCHEME_CALLBACK (x_aligned_on_self, (SCM element));
   DECLARE_SCHEME_CALLBACK (y_aligned_on_self, (SCM element));
@@ -44,8 +42,6 @@ struct Self_alignment_interface
   DECLARE_SCHEME_CALLBACK (centered_on_x_parent, (SCM element));
   DECLARE_SCHEME_CALLBACK (centered_on_y_parent, (SCM element));
   DECLARE_SCHEME_CALLBACK (x_centered_on_y_parent, (SCM element));
-  DECLARE_SCHEME_CALLBACK (avoid_x_colliding_grobs, (SCM element, SCM offset));
-  DECLARE_SCHEME_CALLBACK (x_colliding_grobs, (SCM element));
   DECLARE_SCHEME_CALLBACK (aligned_on_x_parent, (SCM element));
   DECLARE_SCHEME_CALLBACK (aligned_on_y_parent, (SCM element));
 };
index edb6dc6a7a09ce72e75d37e1a5a5dfa6a2c58890..e7c1637471bdbedf4052acf45f73400d92a2704d 100644 (file)
@@ -42,14 +42,11 @@ public:
 
   static SCM aligned_side (Grob *me, Axis a, bool pure, int start, int end, Real *current_off_ptr);
 
-  static SCM general_side_position (Grob *, Axis, bool, bool my_extents,
-                                    bool pure, int start, int end, Real *current_off);
-  static SCM skyline_side_position (Grob *me, Axis a, bool pure, int start, int end, Real *current_offset);
-
   static Axis get_axis (Grob *);
   static void set_axis (Grob *, Axis);
   DECLARE_GROB_INTERFACE ();
   static void add_support (Grob *, Grob *);
+  static void recursive_add_support (Grob *, Grob *);
   static void add_staff_support (Grob *);
 };
 
index c300895fee11bed4e109a896bb3989529b2b59c1..9a5473ddd50e708edcee23b7b6468dfafbef03c6 100644 (file)
@@ -92,6 +92,7 @@ public:
   Real max_height_position () const;
   Real left () const;
   Real right () const;
+  Direction direction () const;
   void set_minimum_height (Real height);
   void clear ();
   bool is_empty () const;
index b0f67afa747296db7645cc02d6e700e3d28c5f64..d26e3e0d2887dde7ae79e999dcde65a9f4948044 100644 (file)
@@ -19,7 +19,7 @@
 */
 
 #include "interval-minefield.hh"
-#include "grob.hh"
+
 Interval_minefield::Interval_minefield (Interval feasible_placements, Real bulk)
 {
   feasible_placements_ = feasible_placements;
index 47718a2fec86d906e0b3ce0adb7211c17f07237b..df06f790dfb00e8f6201682fe3466c22ff0524ee 100644 (file)
@@ -115,6 +115,21 @@ Multi_measure_rest::print (SCM smob)
   return mol.smobbed_copy ();
 }
 
+MAKE_SCHEME_CALLBACK (Multi_measure_rest, height, 1);
+SCM
+Multi_measure_rest::height (SCM smob)
+{
+  Grob *me = unsmob_grob (smob);
+  Spanner *sp = dynamic_cast<Spanner *> (me);
+
+  Real space = 1000000; // something very large...
+
+  Stencil mol;
+  mol.add_stencil (symbol_stencil (me, space));
+
+  return ly_interval2scm (mol.extent (Y_AXIS));
+}
+
 int
 calc_closest_duration_log (Grob *me, double duration, bool force_round_up, bool paranoid)
 {
index 749f9aaa164c496b4c9267df920f13db75ba9cdc..cd7db644a66f409ebdc46f3ee151a76f870fc010 100644 (file)
@@ -272,7 +272,6 @@ New_dynamic_engraver::acknowledge_note_column (Grob_info info)
         {
           script_->set_parent (x_parent, X_AXIS);
           Self_alignment_interface::set_center_parent (script_, X_AXIS);
-          Self_alignment_interface::avoid_x_collisions (script_);
         }
       if (stem)
         Pointer_group_interface::add_grob (script_, ly_symbol2scm ("potential-X-colliding-grobs"), stem);
index 574591a23e8e53e1428d5fb0b431d793000dea9b..a605f0f4ae7e4f574245c84a054e83b93ec58b93 100644 (file)
@@ -194,7 +194,7 @@ New_fingering_engraver::position_scripts (SCM orientations,
                                           vector<Finger_tuple> *scripts)
 {
   for (vsize i = 0; i < scripts->size (); i++)
-    if (stem_ && to_boolean (scripts->at (i).script_->get_property ("add-stem-support")))
+    if (stem_)
       {
         Side_position_interface::add_support (scripts->at (i).script_, stem_);
         if (Grob *flag = unsmob_grob (stem_->get_object ("flag")))
index 045563d457b9acd572a203788fb5dea3d4dab336..79888348f9ce48a7fe7e69445924434941f8a2e8 100644 (file)
@@ -68,11 +68,19 @@ Pointer_group_interface::find_grob (Grob *me, SCM sym, bool (*pred) (Grob *))
   return 0;
 }
 
+// If the grob array is unordered, we assume that duplicates should
+// be removed. This makes sense for things like side-position-elements,
+// which may be added recursively numerous times and thus will eat up
+// computation time when skylines are calculated.
+// If the array is ordered, then we don't remove duplicates.
+
 void
 Pointer_group_interface::add_grob (Grob *me, SCM sym, Grob *p)
 {
   Grob_array *arr = get_grob_array (me, sym);
   arr->add (p);
+  if (!arr->ordered ())
+    arr->remove_duplicates ();
 }
 
 void
@@ -81,6 +89,7 @@ Pointer_group_interface::add_unordered_grob (Grob *me, SCM sym, Grob *p)
   Grob_array *arr = get_grob_array (me, sym);
   arr->add (p);
   arr->set_ordered (false);
+  arr->remove_duplicates ();
 }
 
 static vector<Grob *> empty_array;
index 0a014a38008bb3e57aafb92a3671aa90b0c8ac95..d0486ea4aa1efbe52d52a57f53048749da435dd0 100644 (file)
@@ -156,7 +156,7 @@ Script_column::order_grobs (vector<Grob *> grobs)
                 use it as a support for the current grob
               */
               if (!scm_is_number (last_outside_staff))
-                Side_position_interface::add_support (g, last);
+                Side_position_interface::recursive_add_support (g, last);
               /*
                 if outside_staff_priority is missing or is equal to original
                 outside_staff_priority of previous grob, set new
index ff2b5bfd59ed3bea08a0d77335111f4427091d3f..59adfc3e6ca04d878349f6e3425843c703694c45 100644 (file)
@@ -158,86 +158,6 @@ Self_alignment_interface::aligned_on_parent (Grob *me, Axis a)
   return scm_from_double (x);
 }
 
-MAKE_SCHEME_CALLBACK (Self_alignment_interface, avoid_x_colliding_grobs, 2);
-SCM
-Self_alignment_interface::avoid_x_colliding_grobs (SCM smob, SCM o)
-{
-  SCM avoided = avoid_colliding_grobs (unsmob_grob (smob), X_AXIS, robust_scm2double (o, 0.0));
-  return scm_is_null (avoided) ? o : avoided;
-}
-
-MAKE_SCHEME_CALLBACK (Self_alignment_interface, x_colliding_grobs, 1);
-SCM
-Self_alignment_interface::x_colliding_grobs (SCM smob)
-{
-  Grob *me = unsmob_grob (smob);
-  extract_grob_set (me, "potential-X-colliding-grobs", pot);
-  vector<Grob *> act;
-  Direction d = get_grob_direction (me->get_parent (Y_AXIS));
-  for (vsize i = 0; i < pot.size (); i++)
-    if (d == get_grob_direction (pot[i])
-        && to_boolean (pot[i]->get_property ("cross-staff")))
-      act.push_back (pot[i]);
-
-  SCM grobs_scm = Grob_array::make_array ();
-  unsmob_grob_array (grobs_scm)->set_array (act);
-
-  return grobs_scm;
-}
-
-SCM
-Self_alignment_interface::avoid_colliding_grobs (Grob *me, Axis a, Real offset)
-{
-  extract_grob_set (me, a == X_AXIS ? "X-colliding-grobs" : "Y-colliding-grobs", colls);
-  if (!colls.size ())
-    return SCM_EOL;
-  vector<Interval> ivs;
-
-  Item *refp = dynamic_cast<Item *> (common_refpoint_of_array (colls, me, a));
-  if (!refp)
-    return SCM_EOL;
-
-  Interval iv = me->extent (me, a) + offset;
-  for (vsize i = 0; i < colls.size (); i++)
-    {
-      int my_vai = Grob::get_vertical_axis_group_index (colls[i]);
-      Direction dir = get_grob_direction (colls[i]);
-      // if coll is cross staff but extremal and pointing in the
-      // direction of the extrema, we don't take it into consideration
-      if (Grob *beam = unsmob_grob (colls[i]->get_object ("beam")))
-        {
-          Interval_t<int> vais;
-          extract_grob_set (beam, "normal-stems", stems);
-          for (vsize j = 0; j < stems.size (); j++)
-            vais.add_point (Grob::get_vertical_axis_group_index (stems[j]));
-          // ugh...up and down are different for VerticalAxisGroup order...
-          if ((my_vai == vais[DOWN] && dir == UP)
-              || (my_vai == vais[UP] && dir == DOWN))
-            continue;
-        }
-      ivs.push_back (colls[i]->extent (refp, a));
-    }
-
-  Interval_minefield minefield (Interval (iv.center (), iv.center ()), iv.length ());
-  for (vsize i = 0; i < ivs.size (); i++)
-    minefield.add_forbidden_interval (ivs[i]);
-  minefield.solve ();
-  Interval pos = minefield.feasible_placements ();
-
-  if (pos[LEFT] == pos[RIGHT])
-    return SCM_EOL;
-
-  Direction col_dir = ((abs (pos[LEFT] - iv.center ())
-                        + robust_scm2double (me->get_property ("collision-bias"), 0.0))
-                       > abs (pos[RIGHT] - iv.center ()))
-                      ? RIGHT
-                      : LEFT;
-
-  return scm_from_double ((pos[col_dir] - (iv.length () / 2)
-                           + col_dir
-                           * robust_scm2double (me->get_property ("collision-padding"), 0.0)));
-}
-
 void
 Self_alignment_interface::set_center_parent (Grob *me, Axis a)
 {
@@ -246,12 +166,6 @@ Self_alignment_interface::set_center_parent (Grob *me, Axis a)
                        a);
 }
 
-void
-Self_alignment_interface::avoid_x_collisions (Grob *me)
-{
-  chain_offset_callback (me, avoid_x_colliding_grobs_proc, X_AXIS);
-}
-
 void
 Self_alignment_interface::set_align_self (Grob *me, Axis a)
 {
index b515aa3d5277835828b339b8252ed88e3c829de9..49c6ece55a1c8853214e28965a7c253df284f5da 100644 (file)
@@ -32,6 +32,8 @@ using namespace std;
 #include "directional-element-interface.hh"
 #include "grob.hh"
 #include "grob-array.hh"
+#include "international.hh"
+#include "item.hh"
 #include "main.hh"
 #include "misc.hh"
 #include "note-head.hh"
@@ -51,35 +53,13 @@ Side_position_interface::add_support (Grob *me, Grob *e)
   Pointer_group_interface::add_unordered_grob (me, ly_symbol2scm ("side-support-elements"), e);
 }
 
-SCM
-finish_offset (Grob *me, Direction dir, Real total_off, Real *current_offset)
+void
+Side_position_interface::recursive_add_support (Grob *me, Grob *e)
 {
-  Real ss = Staff_symbol_referencer::staff_space (me);
-  Real minimum_space = ss * robust_scm2double (me->get_property ("minimum-space"), -1);
-  total_off += dir * ss * robust_scm2double (me->get_property ("padding"), 0);
-
-  if (minimum_space >= 0
-      && dir
-      && total_off * dir < minimum_space)
-    total_off = minimum_space * dir;
-
-  if (current_offset)
-    total_off = dir * max (dir * total_off,
-                           dir * (*current_offset));
-
-  /* FIXME: 1000 should relate to paper size.  */
-  if (fabs (total_off) > 1000)
-    {
-      string msg
-        = String_convert::form_string ("Improbable offset for grob %s: %f",
-                                       me->name ().c_str (), total_off);
-
-      programming_error (msg);
-      if (strict_infinity_checking)
-        scm_misc_error (__FUNCTION__, "Improbable offset.", SCM_EOL);
-    }
-
-  return scm_from_double (total_off);
+  Pointer_group_interface::add_unordered_grob (me, ly_symbol2scm ("side-support-elements"), e);
+  extract_grob_set (e, "side-support-elements", sse);
+  for (vsize i = 0; i < sse.size (); i++)
+    recursive_add_support (me, sse[i]);
 }
 
 set<Grob *>
@@ -110,145 +90,167 @@ get_support_set (Grob *me)
   return support;
 }
 
-/* Put the element next to the support, optionally taking in
-   account the extent of the support.
-
-   Does not take into account the extent of ME.
+/*
+  Position next to support, taking into account my own dimensions and padding.
 */
 SCM
-Side_position_interface::general_side_position (Grob *me, Axis a, bool use_extents,
-                                                bool include_my_extent,
-                                                bool pure, int start, int end,
-                                                Real *current_offset)
+axis_aligned_side_helper (SCM smob, Axis a, bool pure, int start, int end, SCM current_off_scm)
 {
-  set<Grob *> support = get_support_set (me);
-
-  Grob *common = common_refpoint_of_array (support, me->get_parent (a), a);
-  Grob *staff_symbol = Staff_symbol_referencer::get_staff_symbol (me);
-  bool include_staff
-    = staff_symbol
-      && a == Y_AXIS
-      && scm_is_number (me->get_property ("staff-padding"))
-      && !to_boolean (me->get_property ("quantize-position"));
-
-  Interval dim;
-  Interval staff_extents;
-  if (include_staff)
+  Real r;
+  Real *current_off_ptr = 0;
+  if (scm_is_number (current_off_scm))
     {
-      common = staff_symbol->common_refpoint (common, Y_AXIS);
-      staff_extents = staff_symbol->maybe_pure_extent (common, Y_AXIS, pure, start, end);
-
-      if (include_staff)
-        dim.unite (staff_extents);
+      r = scm_to_double (current_off_scm);
+      current_off_ptr = &r;
     }
 
-  Direction dir = get_grob_direction (me);
-
-  set<Grob *>::iterator it;
-
-  for (it = support.begin (); it != support.end (); it++)
-    {
-      Grob *e = *it;
+  Grob *me = unsmob_grob (smob);
+  // We will only ever want widths of spanners after line breaking
+  // so we can set pure to false
+  if (dynamic_cast<Spanner *> (me) && a == X_AXIS)
+    pure = false;
 
-      // In the case of a stem, we will find a note head as well
-      // ignoring the stem solves cyclic dependencies if the stem is
-      // attached to a cross-staff beam.
-      if (a == Y_AXIS
-          && Stem::has_interface (e)
-          && dir == - get_grob_direction (e))
-        continue;
+  return Side_position_interface::aligned_side (me, a, pure, start, end, current_off_ptr);
+}
 
-      if (e)
-        {
-          if (use_extents)
-            dim.unite (e->maybe_pure_extent (common, a, pure, start, end));
-          else
-            {
-              Real x = e->maybe_pure_coordinate (common, a, pure, start, end);
-              dim.unite (Interval (x, x));
-            }
-        }
-    }
+MAKE_SCHEME_CALLBACK_WITH_OPTARGS (Side_position_interface, x_aligned_side, 2, 1, "");
+SCM
+Side_position_interface::x_aligned_side (SCM smob, SCM current_off)
+{
+  // Because horizontal skylines need vertical heights, we'd trigger
+  // unpure calculations too soon if this were called before line breaking.
+  // So, we always use pure heights.  Given that horizontal skylines are
+  // almost always used before line breaking anyway, this doesn't cause
+  // problems.
+  return axis_aligned_side_helper (smob, X_AXIS, true, 0, 0, current_off);
+}
 
-  if (dim.is_empty ())
-    dim = Interval (0, 0);
+MAKE_SCHEME_CALLBACK_WITH_OPTARGS (Side_position_interface, y_aligned_side, 2, 1, "");
+SCM
+Side_position_interface::y_aligned_side (SCM smob, SCM current_off)
+{
+  return axis_aligned_side_helper (smob, Y_AXIS, false, 0, 0, current_off);
+}
 
-  Real off = me->get_parent (a)->maybe_pure_coordinate (common, a, pure, start, end);
+MAKE_SCHEME_CALLBACK_WITH_OPTARGS (Side_position_interface, pure_y_aligned_side, 4, 1, "");
+SCM
+Side_position_interface::pure_y_aligned_side (SCM smob, SCM start, SCM end, SCM cur_off)
+{
+  return axis_aligned_side_helper (smob, Y_AXIS, true,
+                                   scm_to_int (start),
+                                   scm_to_int (end),
+                                   cur_off);
+}
 
-  Real total_off = dim.linear_combination (dir) - off;
-  if (include_my_extent)
-    {
-      Interval iv = me->maybe_pure_extent (me, a, pure, start, end);
-      if (!iv.is_empty ())
-        {
-          if (!dir)
-            {
-              programming_error ("direction unknown, but aligned-side wanted");
-              dir = DOWN;
-            }
-          total_off += -iv[-dir];
-        }
-    }
+MAKE_SCHEME_CALLBACK (Side_position_interface, calc_cross_staff, 1)
+SCM
+Side_position_interface::calc_cross_staff (SCM smob)
+{
+  Grob *me = unsmob_grob (smob);
+  extract_grob_set (me, "side-support-elements", elts);
+// Commented out because of cross staff issues
+// Direction for cross staff stems depends on the spacing of staves,
+// which depends on the inclusion of cross-staff side position grobs,
+// which need the direction for positioning.  So the get_grob_direction call
+// may lead to circular dependencies.
+// #if 0
+  Direction my_dir = get_grob_direction (me) ;
+
+  // if a cross-staff grob is pointing in a different direction than
+  // that of an aligning element, we assume that the alignment
+  // of said element will not be influenced the cross-staffitude
+  // of the grob and thus we do not mark the aligning element
+  // as cross-staff
+  for (vsize i = 0; i < elts.size (); i++)
+    if (to_boolean (elts[i]->get_property ("cross-staff"))
+         && my_dir == get_grob_direction (elts[i]))
+      return SCM_BOOL_T;
+//#endif
+#if 0
+  for (vsize i = 0; i < elts.size (); i++)
+    if (to_boolean (elts[i]->get_property ("cross-staff")))
+      return SCM_BOOL_T;
+#endif
+  Grob *myvag = Grob::get_vertical_axis_group (me);
+  for (vsize i = 0; i < elts.size (); i++)
+    if (myvag != Grob::get_vertical_axis_group (elts[i]))
+      return SCM_BOOL_T;
 
-  return finish_offset (me, dir, total_off, current_offset);
+  return SCM_BOOL_F;
 }
 
+// long function - each stage is clearly marked
+
 SCM
-Side_position_interface::skyline_side_position (Grob *me, Axis a,
-                                                bool pure, int start, int end,
-                                                Real *current_offset)
-{
+Side_position_interface::aligned_side (Grob *me, Axis a, bool pure, int start, int end,
+                                       Real *current_off)
+{//printf (" %s\n", me->name ().c_str ());
+  Direction dir = get_grob_direction (me);
+
   set<Grob *> support = get_support_set (me);
 
   Grob *common[2];
   for (Axis ax = X_AXIS; ax < NO_AXES; incr (ax))
-    common[ax] = common_refpoint_of_array (support, ax == a ? me->get_parent (ax) : me, ax);
+    common[ax] = common_refpoint_of_array (support,
+                                           (ax == a
+                                           ? me->get_parent (ax)
+                                           : me),
+                                           ax);
 
   Grob *staff_symbol = Staff_symbol_referencer::get_staff_symbol (me);
-  Direction dir = get_grob_direction (me);
+
+  bool include_staff
+    = staff_symbol
+      && a == Y_AXIS
+      && scm_is_number (me->get_property ("staff-padding"))
+      && !to_boolean (me->get_property ("quantize-position"));
+
+  if (include_staff)
+    common[Y_AXIS] = staff_symbol->common_refpoint (common[Y_AXIS], Y_AXIS);
 
   Skyline my_dim;
-  Skyline_pair *sp = Skyline_pair::unsmob (me->get_property ("vertical-skylines"));
-  if (sp && a == Y_AXIS && !pure)
+  Skyline_pair *skyp = Skyline_pair::unsmob (
+                         me->get_maybe_pure_property (a == X_AXIS
+                                                      ? "horizontal-skylines"
+                                                      : "vertical-skylines",
+                                                      pure,
+                                                      start,
+                                                      end));
+  if (skyp)
     {
-      Skyline_pair copy = Skyline_pair (*sp);
-      copy.shift (me->relative_coordinate (common[X_AXIS], X_AXIS));
-      copy.raise (me->get_parent (Y_AXIS)->relative_coordinate (common[Y_AXIS], Y_AXIS));
+      // for spanner pure heights, we don't know horizontal spacing,
+      // so a spanner can never have a meaningful x coordiante
+      // we just give it the parents' coordinate because its
+      // skyline will likely be of infinite width anyway
+      // and we don't want to prematurely trigger H spacing
+      Real xc = a == X_AXIS || (pure && dynamic_cast<Spanner *> (me))
+                ? me->get_parent (X_AXIS)->relative_coordinate (common[X_AXIS], X_AXIS)
+                : me->relative_coordinate (common[X_AXIS], X_AXIS);
+      // same here, for X_AXIS spacing, if it's happening, it should only be
+      // before line breaking.  because there is no thing as "pure" x spacing,
+      // we assume that it is all pure
+      Real yc = a == X_AXIS
+                ? me->pure_relative_y_coordinate (common[Y_AXIS], start, end)
+                : me->get_parent (Y_AXIS)->maybe_pure_coordinate (common[Y_AXIS], Y_AXIS, pure, start, end);
+      Skyline_pair copy = Skyline_pair (*skyp);
+      copy.shift (a == X_AXIS ? yc : xc);
+      copy.raise (a == X_AXIS ? xc : yc);
       my_dim = copy[-dir];
     }
   else
-    {
-      Box off;
-      for (Axis ax = X_AXIS; ax < NO_AXES; incr (ax))
-        {
-          if (ax == a)
-            off[ax] = me->get_parent (ax)->maybe_pure_coordinate (common[ax], ax, pure, start, end)
-                      + me->maybe_pure_extent (me, ax, pure, start, end);
-          else
-            off[ax] = me->maybe_pure_extent (common[ax], ax, pure, start, end);
-        }
+    me->warning ("cannot find skylines - strange alignment will follow");
 
-      if (off[X_AXIS].is_empty () || off[Y_AXIS].is_empty ())
-        return scm_from_double (0.0);
-
-      my_dim = Skyline (off, other_axis (a), -dir);
-    }
-  bool include_staff
-    = staff_symbol
-      && a == Y_AXIS
-      && scm_is_number (me->get_property ("staff-padding"))
-      && !to_boolean (me->get_property ("quantize-position"));
 
   vector<Box> boxes;
   vector<Skyline_pair> skyps;
-  Real min_h = dir == LEFT ? infinity_f : -infinity_f;
   set<Grob *>::iterator it;
+  Real max_raise = -dir * infinity_f;
+  bool aligns_to_cross_staff = false;
 
-  map<Grob *, vector<Grob *> > note_column_map; // for parts of a note column
   for (it = support.begin (); it != support.end (); it++)
     {
       Grob *e = *it;
-
+//printf ("    %s\n", e->name ().c_str ());
       // In the case of a stem, we will find a note head as well
       // ignoring the stem solves cyclic dependencies if the stem is
       // attached to a cross-staff beam.
@@ -259,161 +261,111 @@ Side_position_interface::skyline_side_position (Grob *me, Axis a,
 
       if (e)
         {
-           if (Note_column::has_interface (e->get_parent (X_AXIS))
-               && to_boolean (me->get_property ("add-stem-support")))
-             {
-               note_column_map[e->get_parent (X_AXIS)].push_back (e);
-               continue;
-             }
 
-           Skyline_pair *sp = Skyline_pair::unsmob (e->get_property ("vertical-skylines"));
-           if (sp && a == Y_AXIS && !pure)
+           bool cross_staff = to_boolean (e->get_property ("cross-staff"));
+
+           Skyline_pair *sp = Skyline_pair::unsmob
+             (e->get_maybe_pure_property (a == X_AXIS
+                                          ? "horizontal-skylines"
+                                          : "vertical-skylines",
+                                          pure || cross_staff,
+                                          start,
+                                          end));
+
+           aligns_to_cross_staff |= cross_staff;
+           if (sp)
              {
+               Real xc = pure && dynamic_cast<Spanner *> (e)
+                         ? e->get_parent (X_AXIS)->relative_coordinate (common[X_AXIS], X_AXIS)
+                         : e->relative_coordinate (common[X_AXIS], X_AXIS);
+               // same logic as above
+               // we assume horizontal spacing is always pure
+               Real yc = a == X_AXIS
+                         ? e->pure_relative_y_coordinate (common[Y_AXIS], start, end)
+                         : e->maybe_pure_coordinate (common[Y_AXIS], Y_AXIS, pure, start, end);
                Skyline_pair copy = Skyline_pair (*sp);
-               copy.shift (e->relative_coordinate (common[X_AXIS], X_AXIS));
-               copy.raise (e->relative_coordinate (common[Y_AXIS], Y_AXIS));
+               if (a == Y_AXIS
+                   && Stem::has_interface (e)
+                   && to_boolean (me->get_property ("add-stem-support")))
+                 copy[dir].set_minimum_height (copy[dir].max_height ());
+               copy.shift (a == X_AXIS ? yc : xc);
+               copy.raise (a == X_AXIS ? xc : yc);
+               max_raise = minmax (dir, max_raise, a == X_AXIS ? xc : yc);
                skyps.push_back (copy);
-               continue;
              }
-           Box b;
-           for (Axis ax = X_AXIS; ax < NO_AXES; incr (ax))
-             b[ax] = e->maybe_pure_extent (common[ax], ax, pure, start, end);
-
-           if (b[X_AXIS].is_empty () || b[Y_AXIS].is_empty ())
-             continue;
-
-           boxes.push_back (b);
-           min_h = minmax (dir, b[a][-dir], min_h);
+           else { /* no warning*/ }
         }
     }
 
-  // this loop ensures that parts of a note column will be in the same box
-  // pushes scripts and such over stems instead of just over heads
-  for (map<Grob *, vector<Grob *> >::iterator i = note_column_map.begin (); i != note_column_map.end (); i++)
-    {
-      Box big;
-      for (vsize j = 0; j < (*i).second.size (); j++)
-        {
-          Grob *e = (*i).second[j];
-          Box b;
-          for (Axis ax = X_AXIS; ax < NO_AXES; incr (ax))
-            b[ax] = e->maybe_pure_extent (common[ax], ax, pure, start, end);
-
-          if (b[X_AXIS].is_empty () || b[Y_AXIS].is_empty ())
-            continue;
-
-          big.unite (b);
-        }
-      if (!big[X_AXIS].is_empty () && !big[Y_AXIS].is_empty ())
-        boxes.push_back (big);
-    }
-
   Skyline dim (boxes, other_axis (a), dir);
   if (skyps.size ())
     {
       Skyline_pair merged (skyps);
       dim.merge (merged[dir]);
     }
-  if (!boxes.size ())
-    dim.set_minimum_height (0.0);
-  else
-    dim.set_minimum_height (min_h);
 
   if (include_staff)
     {
       Interval staff_extents;
       common[Y_AXIS] = staff_symbol->common_refpoint (common[Y_AXIS], Y_AXIS);
       staff_extents = staff_symbol->maybe_pure_extent (common[Y_AXIS], Y_AXIS, pure, start, end);
-      dim.set_minimum_height (minmax (dir, min_h, staff_extents[dir]));
+      dim.set_minimum_height (staff_extents[dir]);
     }
 
-  Real dist = dim.distance (my_dim, 0.1); // 0.1 m4g1c value...fix...
-  Real total_off = !isinf (dist) ? dir * dist : 0.0;
-
-  return finish_offset (me, dir, total_off, current_offset);
-}
-
-MAKE_SCHEME_CALLBACK (Side_position_interface, y_aligned_on_support_refpoints, 1);
-SCM
-Side_position_interface::y_aligned_on_support_refpoints (SCM smob)
-{
-  return general_side_position (unsmob_grob (smob), Y_AXIS, false, false, false, 0, 0, 0);
-}
-
-MAKE_SCHEME_CALLBACK (Side_position_interface, pure_y_aligned_on_support_refpoints, 3);
-SCM
-Side_position_interface::pure_y_aligned_on_support_refpoints (SCM smob, SCM start, SCM end)
-{
-  return general_side_position (unsmob_grob (smob), Y_AXIS, false, false,
-                                true, scm_to_int (start), scm_to_int (end), 0);
-}
-
-/*
-  Position next to support, taking into account my own dimensions and padding.
-*/
-SCM
-axis_aligned_side_helper (SCM smob, Axis a, bool pure, int start, int end, SCM current_off_scm)
-{
-  Real r;
-  Real *current_off_ptr = 0;
-  if (scm_is_number (current_off_scm))
+  // this seems kinda kludgy, as there is no apparent logic to it
+  // however, it is a holdover from the previous code and
+  // necessary for the InstrumentName grob
+  // TODO: find a better way to deal with this...
+  if (dim.is_empty ())
     {
-      r = scm_to_double (current_off_scm);
-      current_off_ptr = &r;
+      dim = Skyline (dim.direction ());
+      dim.set_minimum_height (0.0);
     }
 
-  return Side_position_interface::aligned_side (unsmob_grob (smob), a, pure, start, end, current_off_ptr);
-}
+  // Ditto - seems kludgy, but this time logic of SystemStartBrackets
+  if (my_dim.is_empty ())
+    {
+      my_dim = Skyline (my_dim.direction ());
+      my_dim.set_minimum_height (isinf (max_raise) ? 0.0 : max_raise);
+    }
 
-MAKE_SCHEME_CALLBACK_WITH_OPTARGS (Side_position_interface, x_aligned_side, 2, 1, "");
-SCM
-Side_position_interface::x_aligned_side (SCM smob, SCM current_off)
-{
-  return axis_aligned_side_helper (smob, X_AXIS, false, 0, 0, current_off);
-}
+  // Many cross-staff grobs do not have good height estimations.
+  // We give the grob the best chance of not colliding by shifting
+  // it to the maximum height in the case of cross-staff alignment.
+  // This means, in other words, that the old way things were done
+  // (using boxes instead of skylines) is just reactivated for
+  // alignment to cross-staff grobs.
+  if (aligns_to_cross_staff)
+    dim.set_minimum_height (dim.max_height ());
 
-MAKE_SCHEME_CALLBACK_WITH_OPTARGS (Side_position_interface, y_aligned_side, 2, 1, "");
-SCM
-Side_position_interface::y_aligned_side (SCM smob, SCM current_off)
-{
-  return axis_aligned_side_helper (smob, Y_AXIS, false, 0, 0, current_off);
-}
+  Real ss = Staff_symbol_referencer::staff_space (me);
+  Real dist = dim.distance (my_dim, robust_scm2double (me->get_property ("horizon-padding"), 0.0));
+  Real total_off = !isinf (dist) ? dir * dist : 0.0;
 
-MAKE_SCHEME_CALLBACK_WITH_OPTARGS (Side_position_interface, pure_y_aligned_side, 4, 1, "");
-SCM
-Side_position_interface::pure_y_aligned_side (SCM smob, SCM start, SCM end, SCM cur_off)
-{
-  return axis_aligned_side_helper (smob, Y_AXIS, true,
-                                   scm_to_int (start),
-                                   scm_to_int (end),
-                                   cur_off);
-}
+  total_off += dir * ss * robust_scm2double (me->get_property ("padding"), 0.0);
 
-MAKE_SCHEME_CALLBACK (Side_position_interface, calc_cross_staff, 1)
-SCM
-Side_position_interface::calc_cross_staff (SCM smob)
-{
-  Grob *me = unsmob_grob (smob);
-  extract_grob_set (me, "side-support-elements", elts);
+  Real minimum_space = ss * robust_scm2double (me->get_property ("minimum-space"), -1);
 
-  for (vsize i = 0; i < elts.size (); i++)
-    if (to_boolean (elts[i]->get_property ("cross-staff")))
-      return SCM_BOOL_T;
+  if (minimum_space >= 0
+      && dir
+      && total_off * dir < minimum_space)
+    total_off = minimum_space * dir;
 
-  Grob *common = common_refpoint_of_array (elts, me->get_parent (Y_AXIS), Y_AXIS);
-  return scm_from_bool (common != me->get_parent (Y_AXIS));
-}
+  if (current_off)
+    total_off = dir * max (dir * total_off,
+                           dir * (*current_off));
 
-SCM
-Side_position_interface::aligned_side (Grob *me, Axis a, bool pure, int start, int end,
-                                       Real *current_off)
-{
-  Direction dir = get_grob_direction (me);
-  bool skyline = to_boolean (me->get_property ("use-skylines"));
+  /* FIXME: 1000 should relate to paper size.  */
+  if (fabs (total_off) > 1000)
+    {
+      string msg
+        = String_convert::form_string ("Improbable offset for grob %s: %f",
+                                       me->name ().c_str (), total_off);
 
-  Real o = scm_to_double (skyline && !pure
-                          ? skyline_side_position (me, a, pure, start, end, current_off)
-                          : general_side_position (me, a, true, true, pure, start, end, current_off));
+      programming_error (msg);
+      if (strict_infinity_checking)
+        scm_misc_error (__FUNCTION__, "Improbable offset.", SCM_EOL);
+    }
 
   /*
     Maintain a minimum distance to the staff. This is similar to side
@@ -429,7 +381,7 @@ Side_position_interface::aligned_side (Grob *me, Axis a, bool pure, int start, i
           Real my_off = me->get_parent (Y_AXIS)->maybe_pure_coordinate (common, Y_AXIS, pure, start, end);
           Real staff_off = staff->maybe_pure_coordinate (common, Y_AXIS, pure, start, end);
           Real ss = Staff_symbol::staff_space (staff);
-          Real position = 2 * (my_off + o - staff_off) / ss;
+          Real position = 2 * (my_off + total_off - staff_off) / ss;
           Real rounded = directed_round (position, dir);
           Grob *head = me->get_parent (X_AXIS);
 
@@ -441,9 +393,9 @@ Side_position_interface::aligned_side (Grob *me, Axis a, bool pure, int start, i
 
                   && abs (Staff_symbol_referencer::get_position (head)) > abs (position)))
             {
-              o += (rounded - position) * 0.5 * ss;
+              total_off += (rounded - position) * 0.5 * ss;
               if (Staff_symbol_referencer::on_line (me, int (rounded)))
-                o += dir * 0.5 * ss;
+                total_off += dir * 0.5 * ss;
             }
         }
       else if (scm_is_number (me->get_property ("staff-padding")) && dir)
@@ -460,12 +412,12 @@ Side_position_interface::aligned_side (Grob *me, Axis a, bool pure, int start, i
           Real staff_position = staff->maybe_pure_coordinate (common, Y_AXIS, pure, start, end);
           Interval staff_extent = staff->maybe_pure_extent (staff, a, pure, start, end);
           Real diff = (dir * staff_extent[dir] + staff_padding
-                       - dir * (o + iv[-dir])
+                       - dir * (total_off + iv[-dir])
                        + dir * (staff_position - parent_position));
-          o += dir * max (diff, 0.0);
+          total_off += dir * max (diff, 0.0);
         }
     }
-  return scm_from_double (o);
+  return scm_from_double (total_off);
 }
 
 void
@@ -552,6 +504,7 @@ ADD_INTERFACE (Side_position_interface,
                "add-stem-support "
                "direction "
                "minimum-space "
+               "horizon-padding "
                "padding "
                "quantize-position "
                "side-axis "
index 1d6e4d5e78e81c2efb24b88a54ddae297035e4fa..ed5f390a017bbfdf59ad773c61d7f77fa0570c1b 100644 (file)
@@ -213,6 +213,7 @@ Skyline::normalize ()
 {
   bool last_empty = false;
   list<Building>::iterator i;
+
   for (i = buildings_.begin (); i != buildings_.end (); i++)
     {
       if (last_empty && i->y_intercept_ == -infinity_f)
@@ -330,11 +331,13 @@ single_skyline (Building b, list<Building> *const ret)
 {
   if (b.end_ > b.start_ + EPS)
     {
-      ret->push_back (Building (-infinity_f, -infinity_f,
-                                -infinity_f, b.start_));
+      if (b.start_ != -infinity_f)
+        ret->push_back (Building (-infinity_f, -infinity_f,
+                                  -infinity_f, b.start_));
       ret->push_back (b);
-      ret->push_back (Building (b.end_, -infinity_f,
-                                -infinity_f, infinity_f));
+      if (b.end_ != infinity_f)
+        ret->push_back (Building (b.end_, -infinity_f,
+                                  -infinity_f, infinity_f));
     }
   else
     {
@@ -553,6 +556,7 @@ Skyline::Skyline (Box const &b, Axis horizon_axis, Direction sky)
   sky_ = sky;
   Building front (b, horizon_axis, sky);
   single_skyline (front, &buildings_);
+  normalize ();
 }
 
 void
@@ -766,6 +770,12 @@ Skyline::max_height () const
   return sky_ * ret;
 }
 
+Direction
+Skyline::direction () const
+{
+  return sky_;
+}
+
 Real
 Skyline::left () const
 {
index d8509a6286c3cf6d3fbab5df7eeab9b4478e7035..601893b5cb23913bbc5d925c31a29edde89aba23 100644 (file)
@@ -50,10 +50,12 @@ when this transforms a point (x,y), the point is written as matrix:
 #include "pointer-group-interface.hh"
 #include "lily-guile.hh"
 #include "real.hh"
+#include "rest.hh"
 #include "stencil.hh"
 #include "string-convert.hh"
 #include "skyline.hh"
 #include "skyline-pair.hh"
+#include "spanner.hh"
 using namespace std;
 
 Real QUANTIZATION_UNIT = 0.2;
@@ -192,12 +194,11 @@ make_draw_line_boxes (vector<Box> &boxes, vector<Drul_array<Offset> > &buildings
   do
     {
       Offset inter_l = get_point_in_y_direction (left, perpendicular_slope (slope), thick / 2, d);
-      Offset inter_r = get_point_in_y_direction (right, perpendicular_slope (slope), thick / 2, d);//printf ("O %4.4f %4.4f\n", inter_l[X_AXIS], inter_r[X_AXIS]);printf ("TRANNY %4.4f %4.4f %4.4f %4.4f %4.4f %4.4f\n", trans.xx, trans.xy, trans.yx, trans.yy, trans.x0, trans.y0);
+      Offset inter_r = get_point_in_y_direction (right, perpendicular_slope (slope), thick / 2, d);
       pango_matrix_transform_point (&trans, &inter_l[X_AXIS], &inter_l[Y_AXIS]);
       pango_matrix_transform_point (&trans, &inter_r[X_AXIS], &inter_r[Y_AXIS]);
       if ((inter_l[X_AXIS] == inter_r[X_AXIS]) || (inter_l[Y_AXIS] == inter_r[Y_AXIS]))
         {
-          //printf ("OO %4.4f %4.4f\n", inter_l[X_AXIS], inter_r[X_AXIS]);
           Box b;
           b.add_point (inter_l);
           b.add_point (inter_r);
@@ -964,38 +965,73 @@ stencil_traverser (PangoMatrix trans, SCM expr)
 }
 
 SCM
-Grob::internal_simple_skylines_from_stencil (SCM smob, Axis a)
+Grob::maybe_pure_internal_simple_skylines_from_extents (Grob *me, Axis a, bool pure, int beg, int end, bool ignore_x, bool ignore_y)
 {
-  Grob *me = unsmob_grob (smob);
-
-  if (to_boolean (me->get_property ("cross-staff")))
+  vector<Box> boxes;
+  // we don't know how far spanners stretch along the X axis before
+  // line breaking. better have them take up the whole thing
+  Interval xex = ignore_x
+                 ? Interval (-infinity_f, infinity_f)
+                 : me->extent (me, X_AXIS);
+
+  // If we're looking at the x exent of a cross staff grob, it could be
+  // very early on in the computation process.  We won't know its height
+  // until way later, so we give a brute force approximation.
+  Interval yex = ignore_y
+                 ? Interval (-infinity_f, infinity_f)
+                 : me->maybe_pure_extent (me, Y_AXIS, pure, beg, end);
+
+  // In horizontal spacing, there are grobs like SystemStartBracket
+  // that take up no vertical spcae.  So, if the y extent is empty,
+  // we use the entire Y extent ot make the X a sort of horizontal wall.
+  // Ditto for vertical spacing and grobs like BassFigureAlginmentPositioning.
+  if (a == Y_AXIS && yex.is_empty ())
+    yex.set_full ();
+
+  if (a == X_AXIS && xex.is_empty ())
+    xex.set_full ();
+
+  if (xex.is_empty () || yex.is_empty ())
     return Skyline_pair ().smobbed_copy ();
 
-  extract_grob_set (me, "elements", elts);
-  if (elts.size ())
-    return internal_skylines_from_element_stencils (smob, a);
+  boxes.push_back (Box (xex, yex));
+  return Skyline_pair (boxes, a).smobbed_copy ();
+}
 
-  Stencil *s = unsmob_stencil (me->get_property ("stencil"));
-  if (!s)
-    return Skyline_pair ().smobbed_copy ();
+MAKE_SCHEME_CALLBACK (Grob, pure_simple_vertical_skylines_from_extents, 3);
+SCM
+Grob::pure_simple_vertical_skylines_from_extents (SCM smob, SCM begscm, SCM endscm)
+{
+  Grob *me = unsmob_grob (smob);
+  int beg = robust_scm2int (begscm, 0);
+  int end = robust_scm2int (endscm, INT_MAX);
+  return maybe_pure_internal_simple_skylines_from_extents (me, X_AXIS, true, beg, end, dynamic_cast<Spanner *> (me), false);
+}
 
-  vector<Box> boxes;
-  boxes.push_back (Box (s->extent (X_AXIS), s->extent (Y_AXIS)));
-  return Skyline_pair (boxes, a).smobbed_copy ();
+MAKE_SCHEME_CALLBACK (Grob, simple_vertical_skylines_from_extents, 1);
+SCM
+Grob::simple_vertical_skylines_from_extents (SCM smob)
+{
+  Grob *me = unsmob_grob (smob);
+  return maybe_pure_internal_simple_skylines_from_extents (me, X_AXIS, false, 0, 0, false, false);
 }
 
-MAKE_SCHEME_CALLBACK (Grob, simple_vertical_skylines_from_stencil, 1);
+MAKE_SCHEME_CALLBACK (Grob, pure_simple_horizontal_skylines_from_extents, 3);
 SCM
-Grob::simple_vertical_skylines_from_stencil (SCM smob)
+Grob::pure_simple_horizontal_skylines_from_extents (SCM smob, SCM begscm, SCM endscm)
 {
-  return internal_simple_skylines_from_stencil (smob, X_AXIS);
+  Grob *me = unsmob_grob (smob);
+  int beg = robust_scm2int (begscm, 0);
+  int end = robust_scm2int (endscm, INT_MAX);
+  return maybe_pure_internal_simple_skylines_from_extents (me, Y_AXIS, true, beg, end, false, to_boolean (me->get_property ("cross-staff")));
 }
 
-MAKE_SCHEME_CALLBACK (Grob, simple_horizontal_skylines_from_stencil, 1);
+MAKE_SCHEME_CALLBACK (Grob, simple_horizontal_skylines_from_extents, 1);
 SCM
-Grob::simple_horizontal_skylines_from_stencil (SCM smob)
+Grob::simple_horizontal_skylines_from_extents (SCM smob)
 {
-  return internal_simple_skylines_from_stencil (smob, Y_AXIS);
+  Grob *me = unsmob_grob (smob);
+  return maybe_pure_internal_simple_skylines_from_extents (me, Y_AXIS, false, 0, 0, false, to_boolean (me->get_property ("cross-staff")));
 }
 
 SCM
index 0b5585a71aea6d3dcf51178fa80e21ccda500d72..c1a3a723cb89a601c2a65dd56719467a38088859 100644 (file)
@@ -489,6 +489,9 @@ units.")
 slur, the closer it is to this height.")
      (hide-tied-accidental-after-break ,boolean? "If set, an accidental
 that appears on a tied note after a line break will not be displayed.")
+     (horizon-padding ,number? "The amount to pad the axis
+along which a @code{Skyline} is built for the
+@code{side-position-interface}.")
      (horizontal-shift ,integer? "An integer that identifies ranking
 of @code{NoteColumn}s for horizontal shifting.  This is used by
 @rinternals{note-collision-interface}.")
index 74040cd60d6e958b4dd86f6a20ee331b0f9f4bb9..47db681b6a92a0699ec34f7cba7dc8949b05291c 100644 (file)
@@ -83,7 +83,6 @@
        (side-axis . ,Y)
        (staff-padding . 0.25)
        (stencil . ,ly:accidental-interface::print)
-       (use-skylines . #t)
        (X-extent . ,ly:accidental-interface::width)
        (X-offset . ,(ly:make-simple-closure
                      `(,+
        (font-family . roman)
        (font-size . -2)
        (non-musical . #t)
+       ;; w/o padding, bars numbers are not positioned over the staff as
+       ;; they are slightly to the left. so we add just a bit.
+       (horizon-padding . 0.05)
        (outside-staff-priority . 100)
        (padding . 1.0)
        (self-alignment-X . ,RIGHT)
                        (next-note . (extra-space . 1.0))
                        (right-edge . (extra-space . 0.5))))
        (stencil . ,ly:clef::print)
+       (vertical-skylines . ,ly:grob::vertical-skylines-from-stencil)
        (Y-offset . ,ly:staff-symbol-referencer::callback)
        (meta . ((class . Item)
                  (object-callbacks . ((pure-Y-common . ,ly:axis-group-interface::calc-pure-y-common)
        (slur-padding . 0.3)
        (staff-padding . 0.1)
        (vertical-skylines . ,ly:grob::vertical-skylines-from-element-stencils)
-       (use-skylines . #t)
        (X-extent . ,ly:axis-group-interface::width)
        (Y-extent . ,ly:axis-group-interface::height)
        (Y-offset . ,ly:side-position-interface::y-aligned-side)
        (X-offset . ,ly:self-alignment-interface::x-aligned-on-self)
        (Y-offset . ,ly:self-alignment-interface::y-aligned-on-self)
        (meta . ((class . Item)
-                (object-callbacks . ((X-colliding-grobs . ,ly:self-alignment-interface::x-colliding-grobs)))
                 (interfaces . (dynamic-interface
                                dynamic-text-interface
                                font-interface
      . (
 
        ;; sync with TextScript (?)
-
+       (add-stem-support . ,only-if-beamed)
        (avoid-slur . around)
        (cross-staff . ,script-or-side-position-cross-staff)
        (direction . ,ly:script-interface::calc-direction)
        (thick-thickness . 6.6)
        ;; See Wanske pp. 125
        (usable-duration-logs . ,(iota 4 -3))
+       (Y-extent . ,ly:multi-measure-rest::height)
        (Y-offset . ,ly:staff-symbol-referencer::callback)
        (meta . ((class . Spanner)
                 (interfaces . (font-interface
                        ,(ly:make-simple-closure
                          (list ly:self-alignment-interface::x-centered-on-y-parent)))))
        (Y-offset . ,ly:side-position-interface::y-aligned-side)
+       (vertical-skylines . ,ly:grob::vertical-skylines-from-stencil)
        (meta . ((class . Spanner)
                 (interfaces . (font-interface
                                multi-measure-interface
                        ,(ly:make-simple-closure
                          (list ly:self-alignment-interface::x-aligned-on-self)))))
        (Y-offset . ,ly:side-position-interface::y-aligned-side)
+       (vertical-skylines . ,ly:grob::vertical-skylines-from-stencil)
        (meta . ((class . Spanner)
                 (interfaces . (font-interface
                                multi-measure-interface
      . (
        (axes . (,X ,Y))
        (bound-alignment-interfaces . (rhythmic-head-interface stem-interface))
+       (cross-staff . ,ly:axis-group-interface::cross-staff)
        (horizontal-skylines . ,ly:separation-item::calc-skylines)
        (skyline-vertical-padding . 0.15)
        (X-extent . ,ly:axis-group-interface::width)
                        ,(ly:make-simple-closure
                          (list ly:self-alignment-interface::centered-on-x-parent)))))
        (Y-offset . ,ly:side-position-interface::y-aligned-side)
+       (vertical-skylines . ,ly:grob::vertical-skylines-from-stencil)
        (meta . ((class . Item)
                 (interfaces . (font-interface
                                octavate-eight-interface
        (X-extent . ,ly:rest::width)
        (Y-extent . ,ly:rest::height)
        (Y-offset . ,ly:rest::y-offset-callback)
+       (vertical-skylines . ,ly:grob::vertical-skylines-from-stencil)
        (meta . ((class . Item)
                 (interfaces . (font-interface
                                rest-interface
        (staff-padding . 0.25)
 
        (stencil . ,ly:script-interface::print)
-       (use-skylines . #t)
        (vertical-skylines . ,ly:grob::vertical-skylines-from-stencil)
        (X-offset . ,script-interface::calc-x-offset)
        (Y-offset . ,ly:side-position-interface::y-aligned-side)
     (SostenutoPedalLineSpanner
      . (
        (axes . (,Y))
+       (cross-staff . ,ly:side-position-interface::calc-cross-staff)
        (direction . ,DOWN)
        (minimum-space . 1.0)
        (outside-staff-priority . 1000)
     (SustainPedalLineSpanner
      . (
        (axes . (,Y))
+       (cross-staff . ,ly:side-position-interface::calc-cross-staff)
        (direction . ,DOWN)
        (minimum-space . 1.0)
        (outside-staff-priority . 1000)
        (outside-staff-priority . 450)
 
        ;; sync with Fingering ?
-       (padding . 0.5)
+       (padding . 0.3)
 
        (script-priority . 200)
        (side-axis . ,Y)
     (UnaCordaPedalLineSpanner
      . (
        (axes . (,Y))
+       (cross-staff . ,ly:side-position-interface::calc-cross-staff)
        (direction . ,DOWN)
        (minimum-space . 1.0)
        (outside-staff-priority . 1000)
     (,ly:axis-group-interface::height . ,ly:axis-group-interface::pure-height)
     (,ly:beam::rest-collision-callback . ,ly:beam::pure-rest-collision-callback)
     (,ly:flag::calc-y-offset . ,ly:flag::pure-calc-y-offset)
+    (,ly:grob::horizontal-skylines-from-stencil . ,ly:grob::pure-simple-horizontal-skylines-from-extents)
+    (,ly:grob::horizontal-skylines-from-element-stencils . ,ly:grob::pure-simple-horizontal-skylines-from-extents)
+    (,ly:grob::simple-horizontal-skylines-from-extents . ,ly:grob::pure-simple-horizontal-skylines-from-extents)
+    (,ly:grob::simple-vertical-skylines-from-extents . ,ly:grob::pure-simple-vertical-skylines-from-extents)
     (,ly:grob::stencil-height . ,pure-stencil-height)
+    (,ly:grob::vertical-skylines-from-stencil . ,ly:grob::pure-simple-vertical-skylines-from-extents)
+    (,ly:grob::vertical-skylines-from-element-stencils . ,ly:grob::pure-simple-vertical-skylines-from-extents)
     (,ly:hara-kiri-group-spanner::y-extent . ,ly:hara-kiri-group-spanner::pure-height)
     (,ly:rest-collision::force-shift-callback-rest . ,pure-chain-offset-callback)
     (,ly:rest::height . ,ly:rest::pure-height)
 
 (define pure-functions
   (list
+   ly:accidental-interface::horizontal-skylines
    parenthesize-elements
    laissez-vibrer::print
+   ly:multi-measure-rest::height
    ly:rest::y-offset-callback
    ly:staff-symbol-referencer::callback
    ly:staff-symbol::height))
index cd9fb5b9a23ec4c75fd5430ceb8089a56aa5a737..5519bb8263207d5faa33c5ec77ecdfefd324d2bf 100644 (file)
@@ -677,6 +677,15 @@ right (@var{dir}=+1)."
 (define-public (reverse-interval iv)
   (cons (cdr iv) (car iv)))
 
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; boolean
+
+(define (lily-and a b)
+  (and a b))
+
+(define (lily-or a b)
+  (or a b))
+
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; coordinates
 
index c6ed83e6e026929d22ab8374794e17ff134f7ce7..c83fd27ed61ec2fdd603b11c3f2a6224b0cbea63 100644 (file)
      ((ly:grob? cause) (event-cause cause))
      (else #f))))
 
+(define-public (non-event-cause grob)
+  (let ((cause (ly:grob-property  grob 'cause)))
+
+    (cond
+     ((ly:stream-event? cause) (non-event-cause cause))
+     ((ly:grob? cause) cause)
+     (else #f))))
+
 (define-public (grob-interpret-markup grob text)
   (let* ((layout (ly:grob-layout grob))
         (defs (ly:output-def-lookup layout 'text-font-defaults))
    (ly:side-position-interface::calc-cross-staff g)))
 
 
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; side-position stuff
+
+(define-public (only-if-beamed g)
+  (reduce lily-or
+          #f
+          (map (lambda (x)
+                 (ly:grob? (ly:grob-object x 'beam)))
+               (ly:grob-array->list (ly:grob-object g
+                                                    'side-support-elements)))))
+
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; note heads
 
@@ -926,6 +945,9 @@ between the two text elements."
 (define-public ((grob::calc-property-by-copy prop) grob)
   (ly:event-property (event-cause grob) prop))
 
+(define-public ((grob::calc-property-by-non-event-cause prop) grob)
+  (ly:grob-property (non-event-cause grob) prop))
+
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; fret boards