]> git.donarmstrong.com Git - lilypond.git/commitdiff
Rework skyline algorithm for a more compact representation and less fuzzy
authorJoe Neeman <joeneeman@gmail.com>
Fri, 23 Feb 2007 23:09:03 +0000 (10:09 +1100)
committerJoe Neeman <joeneeman@gmail.com>
Fri, 23 Feb 2007 23:09:03 +0000 (10:09 +1100)
comparisons.
Include minimum-Y-extent boxes in vertical skylines.
Make skyline debugging more verbose.
Include arpeggios in separation-item skylines.

14 files changed:
lily/align-interface.cc
lily/arpeggio.cc
lily/axis-group-interface.cc
lily/include/arpeggio.hh
lily/include/axis-group-interface.hh
lily/include/separation-item.hh
lily/include/skyline.hh
lily/include/system.hh
lily/prob-scheme.cc
lily/separation-item.cc
lily/skyline.cc
lily/system.cc
scm/define-grob-properties.scm
scm/define-grobs.scm

index 6011a79c52929900c28a6c3e5f90c8666c986bc9..45761f40c8a6cd7a2ffa8ec1dd83bcb1f114f971 100644 (file)
@@ -123,7 +123,9 @@ get_skylines (Grob *me,
         to some absolute reference point */
       if (!pure)
        {
-         Skyline_pair *skys = Skyline_pair::unsmob (g->get_property ("skylines"));
+         Skyline_pair *skys = Skyline_pair::unsmob (g->get_property (a == Y_AXIS
+                                                                     ? "vertical-skylines"
+                                                                     : "horizontal-skylines"));
          if (skys)
            skylines = *skys;
 
index 234dbc44e3bd2575b9ffc5b87f9284ad49d7c4dc..56066912fb6e156a87ba938cba89bfc1118b7592 100644 (file)
@@ -147,6 +147,41 @@ Arpeggio::width (SCM smob)
   return ly_interval2scm (arpeggio.extent (X_AXIS));
 }
 
+MAKE_SCHEME_CALLBACK (Arpeggio, height, 1);
+SCM
+Arpeggio::height (SCM smob)
+{
+  return Grob::stencil_height (smob);
+}
+
+MAKE_SCHEME_CALLBACK (Arpeggio, pure_height, 3);
+SCM
+Arpeggio::pure_height (SCM smob, SCM, SCM)
+{
+  Grob *me = unsmob_grob (smob);
+  if (to_boolean (me->get_property ("cross-staff")))
+    return ly_interval2scm (Interval ());
+
+  return height (smob);
+}
+
+MAKE_SCHEME_CALLBACK (Arpeggio, calc_cross_staff, 1);
+SCM
+Arpeggio::calc_cross_staff (SCM smob)
+{
+  Grob *me = unsmob_grob (smob);
+  extract_grob_set (me, "stems", stems);
+
+  for (vsize i = 1; i < stems.size (); i++)
+    {
+      Grob *s1 = Staff_symbol_referencer::get_staff_symbol (stems[i-1]);
+      Grob *s2 = Staff_symbol_referencer::get_staff_symbol (stems[i]);
+      if (s1 != s2)
+       return SCM_BOOL_T;
+    }
+  return SCM_BOOL_F;
+}
+
 ADD_INTERFACE (Arpeggio,
               "Functions and settings for drawing an arpeggio symbol (a wavy line left to noteheads.",
 
index 7f6d1ef6b527af167bd0941630f6dae90ec348ac..b62465322eb8044081bd5801b560c3b60ef21ea5 100644 (file)
 #include "grob-array.hh"
 #include "hara-kiri-group-spanner.hh"
 #include "international.hh"
+#include "lookup.hh"
 #include "paper-column.hh"
 #include "paper-score.hh"
 #include "separation-item.hh"
+#include "stencil.hh"
 #include "system.hh"
 #include "warn.hh"
 
@@ -208,7 +210,16 @@ Axis_group_interface::calc_skylines (SCM smob)
 {
   Grob *me = unsmob_grob (smob);
   extract_grob_set (me, "elements", elts);
-  return skyline_spacing (me, elts).smobbed_copy ();
+  Skyline_pair skylines = skyline_spacing (me, elts);
+
+  /* add a minimum-Y-extent-sized box to the skyline */
+  SCM min_y_extent = me->get_property ("minimum-Y-extent");
+  if (is_number_pair (min_y_extent))
+    {
+      Box b (me->extent (me, X_AXIS), ly_scm2interval (min_y_extent));
+      skylines.insert (b, 0, X_AXIS);
+    }
+  return skylines.smobbed_copy ();
 }
 
 /* whereas calc_skylines calculates skylines for axis-groups with a lot of
@@ -230,7 +241,7 @@ Axis_group_interface::combine_skylines (SCM smob)
   Skyline_pair ret;
   for (vsize i = 0; i < elements.size (); i++)
     {
-      SCM skyline_scm = elements[i]->get_property ("skylines");
+      SCM skyline_scm = elements[i]->get_property ("vertical-skylines");
       if (Skyline_pair::unsmob (skyline_scm))
        {
          Real offset = elements[i]->relative_coordinate (y_common, Y_AXIS);
@@ -246,7 +257,8 @@ SCM
 Axis_group_interface::generic_group_extent (Grob *me, Axis a)
 {
   /* trigger the callback to do skyline-spacing on the children */
-  (void) me->get_property ("skylines");
+  if (a == Y_AXIS)
+    (void) me->get_property ("vertical-skylines");
 
   extract_grob_set (me, "elements", elts);
   Grob *common = common_refpoint_of_array (elts, me, a);
@@ -372,18 +384,27 @@ staff_priority_less (Grob * const &g1, Grob * const &g2)
 }
 
 static void
-add_boxes (Grob *me, Grob *x_common, Grob *y_common, vector<Box> *const boxes)
+add_boxes (Grob *me, Grob *x_common, Grob *y_common, vector<Box> *const boxes, Skyline_pair *skylines)
 {
-  /* if we are a parent, consider the children's boxes instead of mine */
-  if (Grob_array *elements = unsmob_grob_array (me->get_object ("elements")))
+  /* if a child has skylines, use them instead of the extent box */
+  if (Skyline_pair *pair = Skyline_pair::unsmob (me->get_property ("vertical-skylines")))
+    {
+      Skyline_pair s = *pair;
+      s.shift (me->relative_coordinate (x_common, X_AXIS));
+      s.raise (me->relative_coordinate (y_common, Y_AXIS));
+      skylines->merge (s);
+    }
+  else if (Grob_array *elements = unsmob_grob_array (me->get_object ("elements")))
     {
       for (vsize i = 0; i < elements->size (); i++)
-       add_boxes (elements->grob (i), x_common, y_common, boxes);
+       add_boxes (elements->grob (i), x_common, y_common, boxes, skylines);
     }
   else if (!scm_is_number (me->get_property ("outside-staff-priority"))
           && !to_boolean (me->get_property ("cross-staff")))
-    boxes->push_back (Box (me->extent (x_common, X_AXIS),
-                          me->extent (y_common, Y_AXIS)));
+    {
+      boxes->push_back (Box (me->extent (x_common, X_AXIS),
+                            me->extent (y_common, Y_AXIS)));
+    }
 }
 
 /* We want to avoid situations like this:
@@ -475,11 +496,14 @@ Axis_group_interface::skyline_spacing (Grob *me, vector<Grob*> elements)
   vsize i = 0;
   vector<Box> boxes;
 
+  Skyline_pair skylines;
   for (i = 0; i < elements.size ()
         && !scm_is_number (elements[i]->get_property ("outside-staff-priority")); i++)
-    add_boxes (elements[i], x_common, y_common, &boxes);
+    add_boxes (elements[i], x_common, y_common, &boxes, &skylines);
 
-  Skyline_pair skylines (boxes, 0, X_AXIS);
+  SCM padding_scm = me->get_property ("skyline-horizontal-padding");
+  Real padding = robust_scm2double (padding_scm, 0.1);
+  skylines.merge (Skyline_pair (boxes, padding, X_AXIS));
   for (; i < elements.size (); i++)
     {
       SCM priority = elements[i]->get_property ("outside-staff-priority");
@@ -491,6 +515,7 @@ Axis_group_interface::skyline_spacing (Grob *me, vector<Grob*> elements)
 
       add_grobs_of_one_priority (&skylines, current_elts, x_common, y_common);
     }
+  skylines.shift (-me->relative_coordinate (x_common, X_AXIS));
   return skylines;
 }
 
@@ -509,6 +534,24 @@ Axis_group_interface::calc_max_stretch (SCM smob)
   return scm_from_double (ret);
 }
 
+extern bool debug_skylines;
+MAKE_SCHEME_CALLBACK (Axis_group_interface, print, 1)
+SCM
+Axis_group_interface::print (SCM smob)
+{
+  if (!debug_skylines)
+    return SCM_BOOL_F;
+
+  Grob *me = unsmob_grob (smob);
+  Stencil ret;
+  if (Skyline_pair *s = Skyline_pair::unsmob (me->get_property ("vertical-skylines")))
+    {
+      ret.add_stencil (Lookup::points_to_line_stencil (0.1, (*s)[UP].to_points (X_AXIS)).in_color (255, 0, 255));
+      ret.add_stencil (Lookup::points_to_line_stencil (0.1, (*s)[DOWN].to_points (X_AXIS)).in_color (0, 255, 255));
+    }
+  return ret.smobbed_copy ();
+}
+
 ADD_INTERFACE (Axis_group_interface,
 
               "An object that groups other layout objects.",
@@ -522,6 +565,6 @@ ADD_INTERFACE (Axis_group_interface,
               "max-stretch "
               "pure-Y-common "
               "pure-relevant-elements "
-              "skylines "
+              "vertical-skylines "
               "cached-pure-extents "
               );
index b58fd9e299b6db645c8e3347510dc5a5f6dd3d7e..7b0fe264b66c35ce7d031025e392e52b2d2888fd 100644 (file)
@@ -19,6 +19,9 @@ public:
   DECLARE_SCHEME_CALLBACK (print, (SCM));
   DECLARE_SCHEME_CALLBACK (brew_chord_bracket, (SCM));
   DECLARE_SCHEME_CALLBACK (width, (SCM));
+  DECLARE_SCHEME_CALLBACK (height, (SCM));
+  DECLARE_SCHEME_CALLBACK (pure_height, (SCM, SCM, SCM));
+  DECLARE_SCHEME_CALLBACK (calc_cross_staff, (SCM));
   DECLARE_GROB_INTERFACE();
 };
 
index 2f4f501cee8db919a9f7992f9d030c51f45a1f4e..de6cd01ad7608104b6ac2eabf1df2f8678b301d1 100644 (file)
@@ -26,6 +26,7 @@ struct Axis_group_interface
   DECLARE_SCHEME_CALLBACK (calc_skylines, (SCM smob));
   DECLARE_SCHEME_CALLBACK (combine_skylines, (SCM smob));
   DECLARE_SCHEME_CALLBACK (calc_max_stretch, (SCM smob));
+  DECLARE_SCHEME_CALLBACK (print, (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 5bcb4e6e3ea5576cce909e7d9a4f630a9847d02b..1b2471118dff16a64492f2b03bc75523988f2fe2 100644 (file)
@@ -16,8 +16,9 @@
 
 struct Separation_item
 {
-  DECLARE_GROB_INTERFACE();
-  DECLARE_SCHEME_CALLBACK(calc_skylines, (SCM));
+  DECLARE_GROB_INTERFACE ();
+  DECLARE_SCHEME_CALLBACK (calc_skylines, (SCM));
+  DECLARE_SCHEME_CALLBACK (print, (SCM));
 
   static vector<Box> boxes (Grob *me, Grob *left);
   static Skyline conditional_skyline (Grob *, Grob *);
index bccac37238d1fbb7948027d92829732aeb87676b..31747b1d431cdc7c03411e026d076f81aa1ec3e2 100644 (file)
 
 struct Building
 {
-  Interval iv_;
-  Drul_array<Real> height_;
-
+  Real end_;
   Real y_intercept_;
   Real slope_;
 
-  void precompute ();
+  void precompute (Real start, Real start_height, Real end_height, Real end);
   Building (Real start, Real start_height, Real end_height, Real end);
   Building (Box const &b, Real horizon_padding, Axis a, Direction d);
   void print () const;
@@ -34,15 +32,8 @@ struct Building
   Real height (Real x) const;
   Real intersection_x (Building const &other) const;
   void leading_part (Real chop);
-  bool conceals_beginning (Building const &other) const;
-  bool conceals (Building const &other) const;
-  bool sane () const;
-  Building sloped_neighbour (Real horizon_padding, Direction d) const;
-
-  bool operator< (Building const &other)
-  {
-    return iv_[LEFT] < other.iv_[LEFT];
-  }
+  bool conceals (Building const &other, Real x) const;
+  Building sloped_neighbour (Real start, Real horizon_padding, Direction d) const;
 };
 
 class Skyline
@@ -53,7 +44,7 @@ private:
   
   void internal_merge_skyline (list<Building>*, list<Building>*,
                               list<Building> *const result);
-  list<Building> internal_build_skyline (list<Building>*);
+  list<Building> internal_build_skyline (list<Box>*, Real, Axis, Direction);
 
   DECLARE_SIMPLE_SMOBS(Skyline);
 public:
@@ -62,7 +53,7 @@ public:
   Skyline (Direction sky);
   Skyline (vector<Box> const &bldgs, Real horizon_padding, Axis a, Direction sky);
   Skyline (Box const &b, Real horizon_padding, Axis a, Direction sky);
-  vector<Offset> to_points () const;
+  vector<Offset> to_points (Axis) const;
   void merge (Skyline const &);
   void insert (Box const &, Real horizon_padding, Axis);
   void print () const;
index 3a5b39ad4e75104cec0d141affe71dd26c78486b..918243d0a0e47e7bc6b40f8f840345e29d57c326 100644 (file)
@@ -20,8 +20,6 @@ class System : public Spanner
 {
   int rank_;
   Grob_array *all_elements_;
-  Skyline_pair skylines_;
-  void build_skylines ();
   void init_elements ();
   friend class Paper_score;    // ugh.
   Paper_score *pscore_;        // ugh.
index 3f729e4894c4407d89536817efffa23eb31e4609..7e0b560912ebf19ed2aae3e64dd3069351d80cd4 100644 (file)
@@ -94,8 +94,8 @@ LY_DEFINE (ly_paper_system_minimum_distance, "ly:paper-system-minimum-distance",
   Real ret = 0;
   Prob *p1 = unsmob_prob (sys1);
   Prob *p2 = unsmob_prob (sys2);
-  Skyline_pair *sky1 = Skyline_pair::unsmob (p1->get_property ("skylines"));
-  Skyline_pair *sky2 = Skyline_pair::unsmob (p2->get_property ("skylines"));
+  Skyline_pair *sky1 = Skyline_pair::unsmob (p1->get_property ("vertical-skylines"));
+  Skyline_pair *sky2 = Skyline_pair::unsmob (p2->get_property ("vertical-skylines"));
 
   if (sky1 && sky2)
     ret = (*sky1)[DOWN].distance ((*sky2)[UP]);
index 0e3a075100402c3fba1432e5a8097171b8c1eef0..8a83e2b7a1e2eefeec1b5bdbaa3e75281fd5b2c1 100644 (file)
@@ -8,6 +8,8 @@
 
 #include "separation-item.hh"
 
+#include "lookup.hh"
+#include "stencil.hh"
 #include "skyline.hh"
 #include "paper-column.hh"
 #include "warn.hh"
@@ -31,8 +33,8 @@ void
 Separation_item::set_skyline_distance (Drul_array<Item *> items,
                                       Real padding)
 {
-  Drul_array<Skyline_pair*> lines (Skyline_pair::unsmob (items[LEFT]->get_property ("skylines")),
-                                  Skyline_pair::unsmob (items[RIGHT]->get_property ("skylines")));
+  Drul_array<Skyline_pair*> lines (Skyline_pair::unsmob (items[LEFT]->get_property ("horizontal-skylines")),
+                                  Skyline_pair::unsmob (items[RIGHT]->get_property ("horizontal-skylines")));
   Skyline right = conditional_skyline (items[RIGHT], items[LEFT]);
   right.merge ((*lines[RIGHT])[LEFT]);
   
@@ -179,6 +181,24 @@ Separation_item::extremal_break_aligned_grob (Grob *me,
   return last_grob;
 }
 
+extern bool debug_skylines;
+MAKE_SCHEME_CALLBACK (Separation_item, print, 1)
+SCM
+Separation_item::print (SCM smob)
+{
+  if (!debug_skylines)
+    return SCM_BOOL_F;
+
+  Grob *me = unsmob_grob (smob);
+  Stencil ret;
+  if (Skyline_pair *s = Skyline_pair::unsmob (me->get_property ("horizontal-skylines")))
+    {
+      ret.add_stencil (Lookup::points_to_line_stencil (0.1, (*s)[LEFT].to_points (Y_AXIS)).in_color (255, 255, 0));
+      ret.add_stencil (Lookup::points_to_line_stencil (0.1, (*s)[RIGHT].to_points (Y_AXIS)).in_color (0, 255, 255));
+    }
+  return ret.smobbed_copy ();
+}
+
 ADD_INTERFACE (Separation_item,
               "Item that computes widths to generate spacing rods. "
               "This is done in concert with @ref{separating-group-spanner-interface}.",
@@ -187,5 +207,5 @@ ADD_INTERFACE (Separation_item,
               "conditional-elements "
               "elements "
               "padding "
-              "skylines "
+              "horizontal-skylines "
               );
index 99452189c65f7784678e82c71c7e94ec3fbd9a60..8c47df70b8f1cbc079c947b1a0bc0379e5364aab 100644 (file)
    but the distance routine does.
 */
 
-/*
-  FIXME:
-
-  * Consider to use
-
-  typedef list<Skyline_point> Skyline;
-  struct Skyline_point
-  {
-    Real x;
-    Drul_array<Real> ys; 
-  };
-
-  this is a cleaner representation, as it doesn't duplicate the X, and
-  doesn't need bogus buildings at infinity  --hwn.
-
-
-  * All the messing around with EPS is very fishy.  There are no
-  complicated numerical algorithms involved, so EPS should not be
-  necessary.
-
-  --hwn
-  
-  
- */
-
-#define EPS 1e-10
-
-static inline bool
-approx_equal (Real x, Real y)
-{
-  return abs (x - y) < EPS || (isinf (x) && isinf (y) && ((x > 0) == (y > 0)));
-}
-
-static inline bool
-approx_greater_than (Real x, Real y)
-{
-  return x > y + EPS;
-}
+/* If we start including very thin buildings, numerical accuracy errors can
+   arise. Therefore, we ignore all buildings that are less than epsilon wide. */
+#define EPS 1e-5
 
-static inline bool
-approx_less_than (Real x, Real y)
-{
-  return x < y - EPS;
-}
-
-static inline bool
-approx_less_equal (Real x, Real y)
-{
-  return x <= y + EPS;
-}
-
-static inline bool
-approx_greater_equal (Real x, Real y)
+static void
+print_buildings (list<Building> const &b)
 {
-  return x >= y - EPS;
+  for (list<Building>::const_iterator i = b.begin (); i != b.end (); i++)
+    i->print ();
 }
 
 void
 Skyline::print () const
 {
-  for (list<Building>::const_iterator i = buildings_.begin ();
-       i != buildings_.end (); i++)
-    {
-      (*i).print ();
-    }
-}
-
-bool
-is_legal_skyline (list<Building> const &buildings)
-{
-  list<Building>::const_iterator i;
-  Real last_x = -infinity_f;
-  for (i = buildings.begin (); i != buildings.end (); i++)
-    {
-      if (i->iv_[LEFT] != last_x)
-       return false;
-      last_x = i->iv_[RIGHT];
-      if (isinf (i->iv_.length ()) && i->height_[LEFT] != i->height_[RIGHT])
-       return false;
-    }
-  return last_x == infinity_f;
+  print_buildings (buildings_);
 }
 
 Building::Building (Real start, Real start_height, Real end_height, Real end)
-  : iv_ (start, end)
 {
-  height_[LEFT] = start_height;
-  height_[RIGHT] = end_height;
-
   if (isinf (start) || isinf (end))
     assert (start_height == end_height);
 
-  precompute ();
+  end_ = end;
+  precompute (start, start_height, end_height, end);
 }
 
 Building::Building (Box const &b, Real horizon_padding, Axis horizon_axis, Direction sky)
 {
+  Real start = b[horizon_axis][LEFT] - horizon_padding;
+  Real end = b[horizon_axis][RIGHT] + horizon_padding;
   Real height = sky * b[other_axis (horizon_axis)][sky];
 
-  iv_ = b[horizon_axis];
-  iv_.widen (horizon_padding + EPS);
-  height_[LEFT] = height;
-  height_[RIGHT] = height;
-
-  if (sane ())
-    precompute ();
+  end_ = end;
+  precompute (start, height, height, end);
 }
 
 void
-Building::precompute ()
+Building::precompute (Real start, Real start_height, Real end_height, Real end)
 {
-  slope_ = (height_[RIGHT] - height_[LEFT]) / (iv_.length ());
-  if (height_[LEFT] == height_[RIGHT]) /* in case they're both infinity */
+  slope_ = (end_height - start_height) / (end - start);
+  if (start_height == end_height) /* if they were both infinite, we would get nan, not 0, from the prev line */
     slope_ = 0;
 
   assert (!isinf (slope_) && !isnan (slope_));
 
-  if (isinf (iv_[START]))
+  if (isinf (start))
     {
-      assert (slope_ == 0);
-      y_intercept_ = height_[LEFT];
+      assert (start_height == end_height);
+      y_intercept_ = start_height;
     }
   else
-    y_intercept_ = height_[LEFT] - slope_ * iv_[START];
+    y_intercept_ = start_height - slope_ * start;
 }
 
 Real 
 Building::height (Real x) const
 {
-  if (isinf (x))
-    return (x > 0) ? height_[RIGHT] : height_[LEFT];
-  return slope_*x + y_intercept_;
+  return isinf (x) ? y_intercept_ : slope_*x + y_intercept_;
 }
 
 void
 Building::print () const
 {
-  printf ("X[%f,%f] -> Y[%f,%f]\n",
-         iv_[LEFT], iv_[RIGHT],
-         height_[LEFT], height_[RIGHT]);
+  printf ("%f x + %f ends at %f\n", slope_, y_intercept_, end_);
 }
 
 Real
 Building::intersection_x (Building const &other) const
 {
-  return (y_intercept_ - other.y_intercept_) / (other.slope_ - slope_);
+  Real ret = (y_intercept_ - other.y_intercept_) / (other.slope_ - slope_);
+  return isnan (ret) ? -infinity_f : ret;
 }
 
 void
 Building::leading_part (Real chop)
 {
-  assert (chop > iv_[LEFT] && chop <= iv_[RIGHT] && !approx_equal (chop, iv_[LEFT]));
-  iv_[RIGHT] = chop;
-  height_[RIGHT] = height (chop);
+  assert (chop <= end_);
+  end_ = chop;
 }
 
 Building
-Building::sloped_neighbour (Real horizon_padding, Direction d) const
+Building::sloped_neighbour (Real start, Real horizon_padding, Direction d) const
 {
-  Real left = iv_[d];
-  Real right = iv_[d] + d * horizon_padding;
-  Real left_height = height_[d];
-  Real right_height = height_[d] - horizon_padding;
+  Real x = (d == LEFT) ? start : end_;
+  Real left = x;
+  Real right = x + d * horizon_padding;
+  Real left_height = height (x);
+  Real right_height = left_height - horizon_padding;
   if (d == LEFT)
     {
       swap (left, right);
@@ -213,88 +138,68 @@ Building::sloped_neighbour (Real horizon_padding, Direction d) const
   return Building (left, left_height, right_height, right);
 }
 
-bool
-Building::sane () const
+static Real
+first_intersection (Building const &b, list<Building> *const s, Real start_x)
 {
-  return approx_less_than (iv_[LEFT], iv_[RIGHT])
-    && !isinf (height_[RIGHT])
-    && !isinf (height_[LEFT]);
-}
+  while (!s->empty () && start_x < b.end_)
+    {
+      Building c = s->front ();
+      if (c.conceals (b, start_x))
+       return start_x;
 
-static void
-skyline_trailing_part (list<Building> *sky, Real x)
-{
-  if (approx_equal (x, sky->front ().iv_[RIGHT]))
-    sky->pop_front ();
-  else
-    assert (x < sky->front ().iv_[RIGHT]);
+      Real i = b.intersection_x (c);
+      if (i > start_x && i <= b.end_ && i <= c.end_)
+       return i;
 
-  if (!sky->empty ())
-    {
-      sky->front ().iv_[LEFT] = x;
-      sky->front ().height_[LEFT] = sky->front ().height (x);
+      start_x = c.end_;
+      if (b.end_ > c.end_)
+       s->pop_front ();
     }
+  return b.end_;
 }
 
 bool
-Building::conceals_beginning (Building const &other) const
+Building::conceals (Building const &other, Real x) const
 {
-  bool w = false;
-  Real h = other.height (iv_[LEFT]);
-  if (approx_equal (height_[LEFT], h))
-    w = slope_ > other.slope_;    
-  else if (height_[LEFT] > h) 
-    w = true;
-  else 
-    w = false;
-
-  return w;
-}
+  if (slope_ == other.slope_)
+    return y_intercept_ > other.y_intercept_;
 
-bool
-Building::conceals (Building const &other) const
-{
-  assert (iv_[LEFT] <= other.iv_[LEFT]);
-  return (iv_[RIGHT] >= other.iv_[RIGHT])
-    && approx_greater_equal (height (other.iv_[LEFT]), other.height_[LEFT])
-    && approx_greater_equal (height (other.iv_[RIGHT]), other.height_[RIGHT]);
+  /* their slopes were not equal, so there is an intersection point */
+  Real i = intersection_x (other);
+  return (i < x && slope_ > other.slope_)
+    || (i > x && slope_ < other.slope_);
 }
 
 void
 Skyline::internal_merge_skyline (list<Building> *s1, list<Building> *s2,
                                 list<Building> *const result)
 {
+  Real x = -infinity_f;
   while (!s1->empty ())
     {
-      if (s2->front ().conceals_beginning (s1->front ()))
+      if (s2->front ().conceals (s1->front (), x))
        swap (s1, s2);
 
       Building b = s1->front ();
-      while (!s2->empty () && b.conceals (s2->front ()))
-       s2->pop_front ();
+      Real end = first_intersection (b, s2, x);
+
       if (s2->empty ())
        {
          result->push_front (b);
          break;
        }
 
-      /* s2 either intersects with b or it ends after b */
-      Real end = infinity_f;
-      Real s2_start_height = s2->front ().height_[LEFT];
-      Real s2_end_height = s2->front ().height_[RIGHT];
-      Real s1_start_height = b.height (s2->front ().iv_[LEFT]);
-      Real s1_end_height = b.height (s2->front ().iv_[RIGHT]);
-      if (approx_greater_than (s2_start_height, s1_start_height))
-       end = s2->front ().iv_[LEFT];
-      else if (approx_greater_than (s2_end_height, s1_end_height))
-       end = b.intersection_x (s2->front ());
-      end = min (end, b.iv_[RIGHT]);
-
-      b.leading_part (end);
-      result->push_front (b);
-
-      skyline_trailing_part (s1, end);
-      skyline_trailing_part (s2, end);
+      /* only include buildings wider than epsilon */
+      if (end > x + EPS)
+       {
+         b.leading_part (end);
+         result->push_front (b);
+       }
+
+      if (end >= s1->front ().end_)
+       s1->pop_front ();
+
+      x = end;
     }
   result->reverse ();
 }
@@ -306,62 +211,85 @@ empty_skyline (list<Building> *const ret)
 }
 
 static void
-single_skyline (Building b, Real horizon_padding, list<Building> *const ret)
+single_skyline (Building b, Real start, Real horizon_padding, list<Building> *const ret)
 {
-  b.iv_.widen (horizon_padding);
-  
-  if (!isinf (b.iv_[RIGHT]))
-    ret->push_front (Building (b.iv_[RIGHT], -infinity_f,
+  bool sloped_neighbours = horizon_padding > 0 && !isinf (start) && !isinf (b.end_);
+  if (!isinf (b.end_))
+    ret->push_front (Building (b.end_ + horizon_padding, -infinity_f,
                               -infinity_f, infinity_f));
-  if (horizon_padding > 0 && !isinf (b.iv_.length ()))
-    ret->push_front (b.sloped_neighbour (horizon_padding, RIGHT));
+  if (sloped_neighbours)
+    ret->push_front (b.sloped_neighbour (start, horizon_padding, RIGHT));
   
-  if (b.iv_[RIGHT] > b.iv_[LEFT])
+  if (b.end_ > start + EPS)
     ret->push_front (b);
 
-  if (horizon_padding > 0 && !isinf (b.iv_.length ()))
-    ret->push_front (b.sloped_neighbour (horizon_padding, LEFT));
-  if (!isinf (b.iv_[LEFT]))
+  if (sloped_neighbours)
+    ret->push_front (b.sloped_neighbour (start, horizon_padding, LEFT));
+
+  if (!isinf (start))
     ret->push_front (Building (-infinity_f, -infinity_f,
-                              -infinity_f, b.iv_[LEFT]));
+                              -infinity_f, start - horizon_padding));
 }
 
-/* remove a non-overlapping set of buildings from BUILDINGS and build a skyline
+/* remove a non-overlapping set of boxes from BOXES and build a skyline
    out of them */
 static list<Building>
-non_overlapping_skyline (list<Building> *const buildings)
+non_overlapping_skyline (list<Box> *const boxes, Real horizon_padding, Axis horizon_axis, Direction sky)
 {
   list<Building> result;
   Real last_end = -infinity_f;
-  list<Building>::iterator i = buildings->begin ();
-  while (i != buildings->end ())
+  list<Box>::iterator i = boxes->begin ();
+  while (i != boxes->end ())
     {
-      if (approx_less_than (i->iv_[LEFT], last_end))
+      Interval iv = (*i)[horizon_axis];
+
+      if (iv[LEFT] - horizon_padding < last_end)
        {
          i++;
          continue;
        }
 
-      if (approx_greater_than (i->iv_[LEFT], last_end))
-       result.push_back (Building (last_end, -infinity_f, -infinity_f, i->iv_[LEFT]));
-      else
-       i->iv_[LEFT] = last_end;
+      if (iv[LEFT] - horizon_padding > last_end + EPS)
+       result.push_front (Building (last_end, -infinity_f, -infinity_f, iv[LEFT] - horizon_padding));
+
+      Building b (*i, horizon_padding, horizon_axis, sky);
+      bool sloped_neighbours = horizon_padding > 0 && !isinf (iv.length ());
+      if (sloped_neighbours)
+       result.push_front (b.sloped_neighbour (iv[LEFT] - horizon_padding, horizon_padding, LEFT));
+      result.push_front (b);
+      if (sloped_neighbours)
+       result.push_front (b.sloped_neighbour (iv[LEFT] - horizon_padding, horizon_padding, RIGHT));
 
-      last_end = i->iv_[RIGHT];
-      list<Building>::iterator j = i;
-      i++;
-      result.splice (result.end (), *buildings, j);
+      list<Box>::iterator j = i++;
+      boxes->erase (j);
+      last_end = result.front ().end_;
     }
   if (last_end < infinity_f)
-    result.push_back (Building (last_end, -infinity_f, -infinity_f, infinity_f));
-  assert (is_legal_skyline (result));
+    result.push_front (Building (last_end, -infinity_f, -infinity_f, infinity_f));
+  result.reverse ();
   return result;
 }
 
+class LessThanBox
+{
+  Axis a_;
+
+public:
+  LessThanBox (Axis a)
+  {
+    a_ = a;
+  }
+
+  bool operator() (Box const &b1, Box const &b2)
+  {
+    return b1[a_][LEFT] < b2[a_][LEFT];
+  }
+};
+
 list<Building>
-Skyline::internal_build_skyline (list<Building> *buildings)
+Skyline::internal_build_skyline (list<Box> *boxes, Real horizon_padding, Axis horizon_axis, Direction sky)
 {
-  vsize size = buildings->size ();
+  vsize size = boxes->size ();
 
   if (size == 0)
     {
@@ -372,14 +300,15 @@ Skyline::internal_build_skyline (list<Building> *buildings)
   else if (size == 1)
     {
       list<Building> result;
-      single_skyline (buildings->front (), 0, &result);
+      single_skyline (Building (boxes->front (), horizon_padding, horizon_axis, sky),
+                     boxes->front ()[horizon_axis][LEFT], horizon_axis, &result);
       return result;
     }
 
   deque<list<Building> > partials;
-  buildings->sort ();
-  while (!buildings->empty ())
-    partials.push_back (non_overlapping_skyline (buildings));
+  boxes->sort (LessThanBox (horizon_axis));
+  while (!boxes->empty ())
+    partials.push_back (non_overlapping_skyline (boxes, horizon_padding, horizon_axis, sky));
 
   /* we'd like to say while (partials->size () > 1) but that's O (n).
      Instead, we exit in the middle of the loop */
@@ -410,6 +339,7 @@ Skyline::Skyline (Skyline const &src)
 {
   sky_ = src.sky_;
  
+  /* doesn't a list's copy constructor do this? -- jneem */
   for (list<Building>::const_iterator i = src.buildings_.begin ();
        i != src.buildings_.end (); i++)
     {
@@ -434,32 +364,26 @@ Skyline::Skyline (Direction sky)
  */
 Skyline::Skyline (vector<Box> const &boxes, Real horizon_padding, Axis horizon_axis, Direction sky)
 {
-  list<Building> bldgs;
+  list<Box> filtered_boxes;
   sky_ = sky;
 
+  Axis vert_axis = other_axis (horizon_axis);
   for (vsize i = 0; i < boxes.size (); i++)
     {
-      Building front (boxes[i], horizon_padding, horizon_axis, sky);
-      if (front.sane ())
-       {
-         bldgs.push_front (front);
-         if (horizon_padding > 0 && !isinf (front.iv_.length ()))
-           {
-             bldgs.push_front (front.sloped_neighbour (horizon_padding, LEFT));
-             bldgs.push_front (front.sloped_neighbour (horizon_padding, RIGHT));
-           }
-       }
+      Interval iv = boxes[i][horizon_axis];
+      iv.widen (horizon_padding);
+      if (iv.length () > EPS && !boxes[i][vert_axis].is_empty ())
+       filtered_boxes.push_front (boxes[i]);
     }
   
-  buildings_ = internal_build_skyline (&bldgs);
-  assert (is_legal_skyline (buildings_));
+  buildings_ = internal_build_skyline (&filtered_boxes, horizon_padding, horizon_axis, sky);
 }
 
 Skyline::Skyline (Box const &b, Real horizon_padding, Axis horizon_axis, Direction sky)
 {
   sky_ = sky;
-  Building front (b, 0, horizon_axis, sky);
-  single_skyline (front, horizon_padding, &buildings_);
+  Building front (b, horizon_padding, horizon_axis, sky);
+  single_skyline (front, b[horizon_axis][LEFT], horizon_padding, &buildings_);
 }
 
 void
@@ -471,7 +395,6 @@ Skyline::merge (Skyline const &other)
   list<Building> my_bld;
   my_bld.splice (my_bld.begin (), buildings_);
   internal_merge_skyline (&other_bld, &my_bld, &buildings_);
-  assert (is_legal_skyline (buildings_));
 }
 
 void
@@ -481,9 +404,8 @@ Skyline::insert (Box const &b, Real horizon_padding, Axis a)
   list<Building> my_bld;
 
   my_bld.splice (my_bld.begin (), buildings_);
-  single_skyline (Building (b, 0, a, sky_), horizon_padding, &other_bld);
+  single_skyline (Building (b, horizon_padding, a, sky_), b[a][LEFT], horizon_padding, &other_bld);
   internal_merge_skyline (&other_bld, &my_bld, &buildings_);
-  assert (is_legal_skyline (buildings_));
 }
 
 void
@@ -491,22 +413,17 @@ Skyline::raise (Real r)
 {
   list<Building>::iterator end = buildings_.end ();
   for (list<Building>::iterator i = buildings_.begin (); i != end; i++)
-    {
-      i->height_[LEFT] += sky_ * r;
-      i->height_[RIGHT] += sky_ * r;
-      i->y_intercept_ += sky_ * r;
-    }
-  assert (is_legal_skyline (buildings_));
+    i->y_intercept_ += sky_ * r;
 }
 
 void
-Skyline::shift (Real r)
+Skyline::shift (Real s)
 {
   list<Building>::iterator end = buildings_.end ();
   for (list<Building>::iterator i = buildings_.begin (); i != end; i++)
     {
-      i->iv_[LEFT] += r;
-      i->iv_[RIGHT] += r;
+      i->end_ += s;
+      i->y_intercept_ -= s * i->slope_;
     }
 }
 
@@ -518,15 +435,18 @@ Skyline::distance (Skyline const &other) const
   list<Building>::const_iterator j = other.buildings_.begin ();
 
   Real dist = -infinity_f;
+  Real start = -infinity_f;
   while (i != buildings_.end () && j != other.buildings_.end ())
     {
-      Interval iv = intersection (i->iv_, j->iv_);
-      dist = max (dist, max (i->height (iv[LEFT]) + j->height (iv[LEFT]),
-                            i->height (iv[RIGHT]) + j->height (iv[RIGHT])));
-      if (i->iv_[RIGHT] <= j->iv_[RIGHT])
+      Real end = min (i->end_, j->end_);
+      Real start_dist = i->height (start) + j->height (start);
+      Real end_dist = i->height (end) + j->height (end);
+      dist = max (dist, max (start_dist, end_dist));
+      if (i->end_ <= j->end_)
        i++;
       else
        j++;
+      start = end;
     }
   return dist;
 }
@@ -539,7 +459,7 @@ Skyline::height (Real airplane) const
   list<Building>::const_iterator i;
   for (i = buildings_.begin (); i != buildings_.end (); i++)
     {
-      if (i->iv_[RIGHT] >= airplane)
+      if (i->end_ >= airplane)
        return sky_ * i->height (airplane);
     }
 
@@ -559,26 +479,29 @@ void
 Skyline::set_minimum_height (Real h)
 {
   Skyline s (sky_);
-  s.buildings_.front ().height_[LEFT] = h * sky_;
-  s.buildings_.front ().height_[RIGHT] = h * sky_;
   s.buildings_.front ().y_intercept_ = h * sky_;
   merge (s);
 }
 
 
 vector<Offset>
-Skyline::to_points () const
+Skyline::to_points (Axis a) const
 {
   vector<Offset> out;
 
+  Real start = -infinity_f;
   for (list<Building>::const_iterator i (buildings_.begin ());
        i != buildings_.end (); i++)
     {
-      if (!isinf (i->iv_[LEFT]) && !isinf (i->height_[LEFT]))
-       out.push_back (Offset (i->iv_[LEFT], sky_ * i->height_[LEFT]));
-      if (!isinf (i->iv_[RIGHT]) && !isinf (i->height_[RIGHT]))
-       out.push_back (Offset (i->iv_[RIGHT], sky_ * i->height_[RIGHT]));
+      out.push_back (Offset (start, sky_ * i->height (start)));
+      out.push_back (Offset (i->end_, sky_ * i->height (i->end_)));
+      start = i->end_;
     }
+
+  if (a == Y_AXIS)
+    for (vsize i = 0; i < out.size (); i++)
+      out[i] = Offset (out[i][Y_AXIS], out[i][X_AXIS]);
+
   return out;
 }
 
index 6e19d0a6f4f83c8a6613cdcb76f2cd7e7ceab0b1..663d654e0b67cd8c916c26ccf061da51fa45c9ee 100644 (file)
@@ -340,7 +340,6 @@ System::get_paper_system ()
   SCM *tail = &exprs;
 
   post_processing ();
-  build_skylines ();
 
   vector<Layer_entry> entries;
   for (vsize j = 0; j < all_elements_->size (); j++)
@@ -388,8 +387,12 @@ System::get_paper_system ()
                                 exprs));
   if (debug_skylines)
     {
-      sys_stencil.add_stencil (Lookup::points_to_line_stencil (0.1, skylines_[UP].to_points ()).in_color (255, 0, 0));
-      sys_stencil.add_stencil (Lookup::points_to_line_stencil (0.1, skylines_[DOWN].to_points ()).in_color (0, 255, 0));
+      Skyline_pair *skylines = Skyline_pair::unsmob (get_property ("vertical-skylines"));
+      if (skylines)
+       {
+         sys_stencil.add_stencil (Lookup::points_to_line_stencil (0.1, (*skylines)[UP].to_points (X_AXIS)).in_color (255, 0, 0));
+         sys_stencil.add_stencil (Lookup::points_to_line_stencil (0.1, (*skylines)[DOWN].to_points (X_AXIS)).in_color (0, 255, 0));
+       }
     }
 
   Grob *left_bound = this->get_bound (LEFT);
@@ -399,7 +402,7 @@ System::get_paper_system ()
 
   /* information that the page breaker might need */
   Grob *right_bound = this->get_bound (RIGHT);
-  pl->set_property ("skylines", skylines_.smobbed_copy ());
+  pl->set_property ("skylines", this->get_property ("skylines"));
   pl->set_property ("page-break-permission", right_bound->get_property ("page-break-permission"));
   pl->set_property ("page-turn-permission", right_bound->get_property ("page-turn-permission"));
   pl->set_property ("page-break-penalty", right_bound->get_property ("page-break-penalty"));
@@ -503,29 +506,6 @@ get_root_system (Grob *me)
   return dynamic_cast<System*> (system_grob); 
 }
 
-void
-System::build_skylines ()
-{
-  vector<Box> boxes;
-  for (vsize i = 0; i < all_elements_->size (); i++)
-    {
-      Grob *g = all_elements_->grob (i);
-      if (!unsmob_stencil (g->get_property ("stencil")))
-       continue;
-
-      Interval xiv = g->extent (this, X_AXIS);
-      Interval yiv = g->extent (this, Y_AXIS);
-      if (!xiv.is_empty () && !yiv.is_empty ())
-       boxes.push_back (Box (xiv, yiv));
-    }
-
-  SCM horizon_padding_scm = get_property ("skyline-horizontal-padding");
-  Real horizon_padding = robust_scm2double (horizon_padding_scm, 0);
-  skylines_[UP] = Skyline (boxes, horizon_padding, X_AXIS, UP);
-  skylines_[DOWN] = Skyline (boxes, horizon_padding, X_AXIS, DOWN);
-}
-
-
 ADD_INTERFACE (System,
               "This is the toplevel object: each object in a score "
               "ultimately has a System object as its X and Y parent. ",
index 7cf4d853f8ea18c8329f0586af2c0e7884f4389d..4c8cc6ef402e4757506f2456a0fc03470adfe5e3 100644 (file)
@@ -357,7 +357,8 @@ note that starts here.")
 object.")
      (side-axis ,number? "If the value is #X (or equivalently 1), the object is placed horizontally next to the other object. If the value is #Y or 0, it is placed vertically.")
      (size ,number? "Size of object, relative to standard size.")
-     (skylines ,ly:skyline-pair? "Two skylines, one above and one below this grob (or, for some grobs, to the left and to the right).")
+     (vertical-skylines ,ly:skyline-pair? "Two skylines, one above and one below this grob.")
+     (horizontal-skylines ,ly:skyline-pair? "Two skylines, one to the left and one to the right of this grob.")
      (slope ,number? "The slope of this object.")
      (slur-padding ,number? "Extra distance between slur and script.")
      (space-alist ,list? "A table that specifies distances between
index 8d81855a1b9a74a441e5606c4a02d4d34259eea6..9497794b805b5078eaef9540060fafd42f56a867 100644 (file)
        (script-priority . 0)
        (side-axis . ,X)
        (staff-position . 0.0)
+       (cross-staff . ,ly:arpeggio::calc-cross-staff)
+       (Y-extent . ,ly:arpeggio::height)
        (meta . ((class . Item)
                 (interfaces . (arpeggio-interface
                                staff-symbol-referencer-interface
      . (
        (axes . (,Y))
        (Y-extent . ,ly:axis-group-interface::height)
-       (skylines . ,ly:axis-group-interface::calc-skylines)
+       (vertical-skylines . ,ly:axis-group-interface::calc-skylines)
        (meta . ((class . Spanner)
                 (interfaces . (axis-group-interface
                                ))))))
        (avoid-slur . inside)
        (X-extent . ,ly:axis-group-interface::width)
        (Y-extent . ,ly:axis-group-interface::height)
-       (skylines . ,ly:separation-item::calc-skylines)
+       (horizontal-skylines . ,ly:separation-item::calc-skylines)
+       (stencil . ,ly:separation-item::print)
        (meta . ((class . Item)
                 (interfaces . (
                                separation-item-interface))))))
        (axes . (0 1))
        (X-extent . ,ly:axis-group-interface::width)
        (Y-extent . ,ly:axis-group-interface::height)
-       (skylines . ,ly:axis-group-interface::calc-skylines)
+       (vertical-skylines . ,ly:axis-group-interface::calc-skylines)
        (max-stretch . ,ly:axis-group-interface::calc-max-stretch)
        (skyline-horizontal-padding . 1.0)
        (meta . ((class . System)
        (X-extent . ,ly:axis-group-interface::width)
        (stacking-dir . -1)
        (padding . 0.5)
-       (skylines . ,ly:axis-group-interface::combine-skylines)
+       (vertical-skylines . ,ly:axis-group-interface::combine-skylines)
        (max-stretch . ,ly:align-interface::calc-max-stretch)
        (meta . ((class . Spanner)
                 (object-callbacks . ((Y-common . ,ly:axis-group-interface::calc-y-common)))
        (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)
-       (skylines . ,ly:hara-kiri-group-spanner::calc-skylines)
+       (vertical-skylines . ,ly:hara-kiri-group-spanner::calc-skylines)
        (max-stretch . ,ly:axis-group-interface::calc-max-stretch)
+       (stencil . ,ly:axis-group-interface::print)
        (meta . ((class . Spanner)
                 (object-callbacks . ((X-common . ,ly:axis-group-interface::calc-x-common)))
                 (interfaces . (axis-group-interface
 
 (define pure-print-callbacks
   (list
+   print-circled-text-callback
+   lyric-text::print
+   ly:arpeggio::print
+   ly:arpeggio::brew-chord-bracket
    ly:bar-line::print
    ly:note-head::print
    ly:dots::print
 (define pure-conversions-alist
   `(
     (,ly:accidental-interface::height . ,ly:accidental-interface::pure-height)
+    (,ly:arpeggio::height . ,ly:arpeggio::pure-height)
     (,ly:slur::outside-slur-callback . ,ly:slur::pure-outside-slur-callback)
     (,ly:stem::height . ,ly:stem::pure-height)
     (,ly:rest::height . ,ly:rest::pure-height)