]> git.donarmstrong.com Git - lilypond.git/commitdiff
Add skyline-based collision resolving for grobs above and below the staff
authorJoe Neeman <joeneeman@gmail.com>
Tue, 21 Nov 2006 07:30:44 +0000 (09:30 +0200)
committerJoe Neeman <joeneeman@gmail.com>
Tue, 21 Nov 2006 07:30:44 +0000 (09:30 +0200)
lily/axis-group-interface.cc
lily/grob.cc
lily/include/axis-group-interface.hh
lily/include/grob.hh
lily/skyline.cc
scm/define-grob-properties.scm
scm/define-grobs.scm

index 02e900164b642b1ba8f358994b7e9884edafa696..366519948d7f8af610714e14f6b5dd1585d9456f 100644 (file)
@@ -9,6 +9,7 @@
 #include "axis-group-interface.hh"
 
 #include "align-interface.hh"
+#include "directional-element-interface.hh"
 #include "pointer-group-interface.hh"
 #include "grob.hh"
 #include "grob-array.hh"
@@ -17,6 +18,7 @@
 #include "item.hh"
 #include "paper-column.hh"
 #include "paper-score.hh"
+#include "std-vector.hh"
 #include "system.hh"
 #include "warn.hh"
 
@@ -251,6 +253,68 @@ Axis_group_interface::get_children (Grob *me, vector<Grob*> *found)
     }
 }
 
+bool
+staff_priority_less (Grob * const &g1, Grob * const &g2)
+{
+  int priority_1 = robust_scm2int (g1->get_property ("outside-staff-priority"), INT_MIN);
+  int priority_2 = robust_scm2int (g2->get_property ("outside-staff-priority"), INT_MIN);
+
+  if (priority_1 < priority_2)
+    return true;
+  else if (priority_1 > priority_2)
+    return false;
+
+  /* if there is no preference in staff priority, choose the one with the lower rank */
+  int rank_1 = g1->spanned_rank_iv ()[LEFT];
+  int rank_2 = g2->spanned_rank_iv ()[LEFT];
+  return rank_1 < rank_2;
+}
+
+MAKE_SCHEME_CALLBACK (Axis_group_interface, skyline_spacing, 1)
+SCM
+Axis_group_interface::skyline_spacing (SCM smob)
+{
+  Grob *me = unsmob_grob (smob);
+  extract_grob_set (me, "elements", ro_elements);
+  vector<Grob*> elements (ro_elements);
+  vector_sort (elements, staff_priority_less);
+  Grob *x_common = common_refpoint_of_array (elements, me, X_AXIS);
+
+  vsize i = 0;
+  vector<Box> boxes;
+  for (i = 0; i < elements.size ()
+        && !scm_is_number (elements[i]->get_property ("outside-staff-priority")); i++)
+    boxes.push_back (Box (elements[i]->extent (x_common, X_AXIS),
+                         elements[i]->extent (me, Y_AXIS)));
+
+  Drul_array<Skyline> skylines (Skyline (boxes, X_AXIS, DOWN),
+                               Skyline (boxes, X_AXIS, UP));
+  for (; i < elements.size (); i++)
+    {
+      Direction dir = get_grob_direction (elements[i]);
+      if (dir == CENTER)
+       {
+         warning (_ ("an outside-staff object should have a direction"));
+         continue;
+       }
+
+      Box b (elements[i]->extent (x_common, X_AXIS),
+            elements[i]->extent (me, Y_AXIS));
+      boxes.clear ();
+      boxes.push_back (b);
+      Skyline other = Skyline (boxes, X_AXIS, -dir);
+      Real dist = skylines[dir].distance (other);
+
+      if (dist > 0)
+       {
+         b.translate (Offset (0, dir*dist));
+         elements[i]->translate_axis (dir*dist, Y_AXIS);
+       }
+      skylines[dir].insert (b, X_AXIS);
+    }
+  return SCM_UNSPECIFIED;
+}
+
 ADD_INTERFACE (Axis_group_interface, "axis-group-interface",
 
               "An object that groups other layout objects.",
index 28f665138cae691ac2bcd883e3be668ec63f0b08..1456a264ef9a8cb12c4adbb4ddf4b008b4ecda31 100644 (file)
@@ -621,6 +621,7 @@ ADD_INTERFACE (Grob, "grob-interface",
               "meta "
               "minimum-X-extent "
               "minimum-Y-extent "
+              "outside-staff-priority "
               "rotation "
               "springs-and-rods "
               "staff-symbol "
index 767271ad34bfda475008db8f72b1f8cdd108d537..3f1dbb407dbdc02fafdc397dfb50c31384a09f3f 100644 (file)
@@ -22,6 +22,7 @@ struct Axis_group_interface
   DECLARE_SCHEME_CALLBACK (width, (SCM smob));
   DECLARE_SCHEME_CALLBACK (height, (SCM smob));
   DECLARE_SCHEME_CALLBACK (pure_height, (SCM smob, SCM start, SCM end));
+  DECLARE_SCHEME_CALLBACK (skyline_spacing, (SCM smob));
   static Interval relative_group_extent (vector<Grob*> const &list,
                                         Grob *common, Axis);
   static Interval relative_pure_height (Grob *me, vector<Grob*> const &list,
index 5eb433921a0c23c8d6295be009921175c0ef65da..64fb7322a69f3065a907d5b9f45e08470e0978e3 100644 (file)
@@ -9,6 +9,7 @@
 #ifndef GROB_HH
 #define GROB_HH
 
+#include "box.hh"
 #include "virtual-methods.hh"
 #include "dimension-cache.hh"
 #include "grob-interface.hh"
index 731652b50559f715f9af945169b28280c8f50816..4cb07fc65fd9bf6b03adbb43ad9840a01703a731 100644 (file)
@@ -153,12 +153,14 @@ Skyline::internal_merge_skyline (list<Building> *s1, list<Building> *s2,
 
       Building b = s1->front ();
       while (s2->front ().iv_[RIGHT] < b.iv_[RIGHT]
-            && s2->front ().end_height_ <= b.height (s2->front ().iv_[RIGHT]))
+            && s2->front ().end_height_ <= b.height (s2->front ().iv_[RIGHT]) + EPS)
        s2->pop_front ();
 
       /* the front of s2 either intersects with b or it ends after b */
       Real end = infinity_f;
-      if (s2->front ().end_height_ > b.height (s2->front ().iv_[RIGHT]))
+      Real s2_end_height = s2->front ().end_height_;
+      Real s1_end_height = b.height (s2->front ().iv_[RIGHT]);
+      if (s2_end_height > s1_end_height + EPS)
        end = b.intersection (s2->front ());
       end = min (end, b.iv_[RIGHT]);
       Real height = b.height (end);
@@ -267,10 +269,11 @@ void
 Skyline::insert (Box const &b, Axis a)
 {
   list<Building> other_bld;
-  list<Building> my_bld (buildings_);
+  list<Building> my_bld;
   Interval iv = b[a];
   Real height = sky_ * b[other_axis (a)][sky_];
 
+  my_bld.splice (my_bld.begin (), buildings_);
   single_skyline (Building (iv[LEFT], height, height, iv[RIGHT], max_slope_), &other_bld, max_slope_);
   internal_merge_skyline (&other_bld, &my_bld, &buildings_);
   assert (is_legal_skyline ());
index 47f0b8c47b6095ca1232af2d5edacbdfc64e98c6..bd30ea9fb979c8e8d113a73fe8ffc5b5097f6100 100644 (file)
@@ -274,6 +274,9 @@ get stems extending to the middle staff line.")
      (non-musical ,boolean? "True if the grob belongs in a NonMusicalPaperColumn.")
      (number-type ,symbol? "Type of numbers to use in label.  Choices
 include @code{roman-lower}, @code{roman-upper}, and @code{arabic}.")
+     (outside-staff-priority ,number? "When set, the grob will be positioned outside the staff
+in such a way as to avoid all collisions. In case of a potential collision, the grob with
+the smaller outside-staff-priority will be closer to the staff.")
      (packed-spacing ,boolean? "If set, the notes are spaced as
 tightly as possible.")
      (padding ,ly:dimension? "Add this much extra space between
index 3b8dd7abbce2e17335990f1f20801afacf8f6a35..46dc0e3ee693741428a615a3f8e350e0fe64bbc2 100644 (file)
        (axes . (0 1))
        (X-extent . ,ly:axis-group-interface::width)
        (Y-extent . ,ly:axis-group-interface::height)
+       (after-line-breaking . ,ly:axis-group-interface::skyline-spacing)
        (meta . ((class . System)
                 (interfaces . (system-interface
                                axis-group-interface))))))
        (Y-offset . ,ly:hara-kiri-group-spanner::force-hara-kiri-callback)
        (Y-extent . ,ly:hara-kiri-group-spanner::y-extent)
        (X-extent . ,ly:axis-group-interface::width)
+       (after-line-breaking . ,ly:axis-group-interface::skyline-spacing)
        (meta . ((class . Spanner)
                 (interfaces . (axis-group-interface
                                hara-kiri-group-interface