]> git.donarmstrong.com Git - lilypond.git/commitdiff
Merge with git+ssh://jneem@git.sv.gnu.org/srv/git/lilypond.git
authorJoe Neeman <joeneeman@gmail.com>
Sun, 26 Nov 2006 17:11:30 +0000 (19:11 +0200)
committerJoe Neeman <joeneeman@gmail.com>
Sun, 26 Nov 2006 17:11:30 +0000 (19:11 +0200)
23 files changed:
lily/accidental-placement.cc
lily/axis-group-interface.cc
lily/beam.cc
lily/grob.cc
lily/include/axis-group-interface.hh
lily/include/grob.hh
lily/include/lily-guile.hh
lily/include/skyline.hh
lily/include/system.hh
lily/include/tie-column-format.hh
lily/include/tie-formatting-problem.hh
lily/instrument-name-engraver.cc
lily/lily-guile.cc
lily/main.cc
lily/program-option.cc
lily/skyline.cc
lily/system.cc
lily/tie-formatting-problem.cc
scm/define-grob-properties.scm
scm/define-grobs.scm
scm/graphviz.scm [new file with mode: 0644]
scm/layout-page-layout.scm
scm/lily.scm

index 02f0c522a2367ceb9c71b23a2dad9f0b8d0f482b..c943c9cca442520c776b6a0c530a63fdfcfa7572 100644 (file)
@@ -110,8 +110,8 @@ Accidental_placement::get_relevant_accidental_extent (Grob *me,
 
 struct Accidental_placement_entry
 {
-  vector<Skyline_entry> left_skyline_;
-  vector<Skyline_entry> right_skyline_;
+  Skyline left_skyline_;
+  Skyline right_skyline_;
   Interval vertical_extent_;
   vector<Box> extents_;
   vector<Grob*> grobs_;
@@ -307,22 +307,16 @@ Accidental_placement::calc_positioning_done (SCM smob)
   for (vsize i = apes.size (); i--;)
     {
       Accidental_placement_entry *ape = apes[i];
-      ape->left_skyline_ = empty_skyline (LEFT);
-      ape->right_skyline_ = empty_skyline (RIGHT);
 
       for (vsize j = apes[i]->grobs_.size (); j--;)
        {
          Grob *a = apes[i]->grobs_[j];
-
          vector<Box> boxes = Accidental_interface::accurate_boxes (a, common);
 
          ape->extents_.insert (ape->extents_.end (), boxes.begin (), boxes.end ());
-         for (vsize j = boxes.size (); j--;)
-           {
-             insert_extent_into_skyline (&ape->left_skyline_, boxes[j], Y_AXIS, LEFT);
-             insert_extent_into_skyline (&ape->right_skyline_, boxes[j], Y_AXIS, RIGHT);
-           }
        }
+      ape->left_skyline_ = Skyline (ape->extents_, Y_AXIS, LEFT);
+      ape->right_skyline_ = Skyline (ape->extents_, Y_AXIS, RIGHT);
     }
 
   Interval total;
@@ -340,16 +334,11 @@ Accidental_placement::calc_positioning_done (SCM smob)
 
   Accidental_placement_entry *head_ape = new Accidental_placement_entry;
   common[X_AXIS] = common_refpoint_of_array (heads, common[X_AXIS], X_AXIS);
-  vector<Skyline_entry> head_skyline (empty_skyline (LEFT));
   
   vector<Box> head_extents;
   for (vsize i = heads.size (); i--;)
-    {
-      Box b (heads[i]->extent (common[X_AXIS], X_AXIS),
-            heads[i]->extent (common[Y_AXIS], Y_AXIS));
-
-      insert_extent_into_skyline (&head_skyline, b, Y_AXIS, LEFT);
-    }
+    head_extents.push_back (Box (heads[i]->extent (common[X_AXIS], X_AXIS),
+                                heads[i]->extent (common[Y_AXIS], Y_AXIS)));
 
   vector<Grob *> stems;
   for (vsize i = 0; i < heads.size  (); i++)
@@ -364,27 +353,24 @@ Accidental_placement::calc_positioning_done (SCM smob)
     {
       int very_large = INT_MAX;
       
-      Box b (heads[i]->extent (common[X_AXIS], X_AXIS),
-            heads[i]->pure_height (common[Y_AXIS], 0, very_large));
-
-      insert_extent_into_skyline (&head_skyline, b, Y_AXIS, LEFT);
+      head_extents.push_back (Box (heads[i]->extent (common[X_AXIS], X_AXIS),
+                                  heads[i]->pure_height (common[Y_AXIS], 0, very_large)));
     }
-  
-  head_ape->left_skyline_ = head_skyline;
+
+  head_ape->left_skyline_ = Skyline (head_extents, Y_AXIS, LEFT);
   head_ape->offset_ = 0.0;
 
   Real padding = robust_scm2double (me->get_property ("padding"), 0.2);
 
-  vector<Skyline_entry> left_skyline = head_ape->left_skyline_;
-  heighten_skyline (&left_skyline,
-                   -robust_scm2double (me->get_property ("right-padding"), 0));
+  Skyline left_skyline = head_ape->left_skyline_;
+  left_skyline.raise (-robust_scm2double (me->get_property ("right-padding"), 0))
+;
   /*
     Add accs entries right-to-left.
   */
   for (vsize i = apes.size (); i-- > 0;)
     {
-      Real offset
-       = -skyline_meshing_distance (apes[i]->right_skyline_, left_skyline);
+      Real offset = -apes[i]->right_skyline_.distance (left_skyline);
       if (isinf (offset))
        offset = (i < apes.size () - 1) ? apes[i + 1]->offset_ : 0.0;
       else
@@ -392,9 +378,9 @@ Accidental_placement::calc_positioning_done (SCM smob)
 
       apes[i]->offset_ = offset;
 
-      vector<Skyline_entry> new_left_skyline = apes[i]->left_skyline_;
-      heighten_skyline (&new_left_skyline, apes[i]->offset_);
-      merge_skyline (&new_left_skyline, left_skyline, LEFT);
+      Skyline new_left_skyline = apes[i]->left_skyline_;
+      new_left_skyline.raise (apes[i]->offset_);
+      new_left_skyline.merge (left_skyline);
       left_skyline = new_left_skyline;
     }
 
index 02e900164b642b1ba8f358994b7e9884edafa696..c7a5b8eff90b5c0cd4b45501465987b94ee381b5 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"
 
@@ -182,6 +184,8 @@ SCM
 Axis_group_interface::generic_group_extent (Grob *me, Axis a)
 {
   extract_grob_set (me, "elements", elts);
+  if (a == Y_AXIS && to_boolean (me->get_property ("skyline-spacing")))
+    skyline_spacing (me, elts);
   Grob *common = common_refpoint_of_array (elts, me, a);
 
   Real my_coord = me->relative_coordinate (common, a);
@@ -251,6 +255,66 @@ 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;
+}
+
+void
+Axis_group_interface::skyline_spacing (Grob *me, vector<Grob*> elements)
+{
+  vector_sort (elements, staff_priority_less);
+  Grob *x_common = common_refpoint_of_array (elements, me, X_AXIS);
+  Grob *y_common = common_refpoint_of_array (elements, me, Y_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 (y_common, 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 (y_common, 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);
+    }
+}
+
 ADD_INTERFACE (Axis_group_interface, "axis-group-interface",
 
               "An object that groups other layout objects.",
@@ -260,5 +324,6 @@ ADD_INTERFACE (Axis_group_interface, "axis-group-interface",
               "elements "
               "common-refpoint-of-elements "
               "pure-relevant-elements "
+              "skyline-spacing "
               "cached-pure-extents "
               );
index dcbed75ce551b560df303f70dbd7118c014a23ed..0778c5838884749ae4a85bb2e912008c0100511a 100644 (file)
@@ -296,6 +296,10 @@ typedef map<int, vector<Beam_stem_segment> >  Position_stem_segments_map;
 vector<Beam_segment>
 Beam::get_beam_segments (Grob *me_grob, Grob **common)
 {
+  /* ugh, this has a side-effect that we need to ensure that
+     Stem #'beaming is correct */
+  (void) me_grob->get_property ("quantized-positions");
+
   Spanner *me = dynamic_cast<Spanner*> (me_grob);
 
   extract_grob_set (me, "stems", stems);
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..b1bd975454aa1e811e90925cde04061d0c869bfd 100644 (file)
@@ -30,6 +30,7 @@ struct Axis_group_interface
   static Interval cached_pure_height (Grob *me, vector<Grob*> const &list,
                                      Grob *common, int, int);
 
+  static void skyline_spacing (Grob *me, vector<Grob*> elements);
   static void add_element (Grob *me, Grob *);
   static void set_axes (Grob *, Axis, Axis);
   static bool has_axis (Grob *, Axis);
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 3422089e9c50e043b884093d37600de8d42e14e3..0f94e2ebbb9000541a4225952c73004a239d63c1 100644 (file)
@@ -114,9 +114,7 @@ inline SCM ly_append4 (SCM x1, SCM x2, SCM x3, SCM x4)
 /*
   display and print newline.
 */
-extern "C" {
-  void ly_display_scm (SCM s);
-}
+void ly_display_scm (void *s);
 
 void read_lily_scm_file (string);
 void ly_c_init_guile ();
index fc8d3acedd14d1f5a680378ee537014b518809a6..c8440c7f9409dfa88ccc758cdbe49713b04763f4 100644 (file)
@@ -1,41 +1,64 @@
 /*
-  skyline.hh -- declare Skyline_entry and funcbs.
+  skyline.hh -- declare Skyline class.
 
   source file of the GNU LilyPond music typesetter
 
-  (c) 2002--2006 Han-Wen Nienhuys <hanwen@xs4all.nl>
+  (c) 2006 Joe Neeman <joeneeman@gmail.com>
 */
 
 #ifndef SKYLINE_HH
 #define SKYLINE_HH
 
-#include "std-vector.hh"
+#include <list>
+#include "axis.hh"
 #include "box.hh"
+#include "interval.hh"
+#include "direction.hh"
+#include "std-vector.hh"
+#include "stencil.hh"
 
-struct Skyline_entry
+struct Building
 {
-  Interval width_;
-  Real height_;
-  Skyline_entry ();
-  Skyline_entry (Interval, Real);
+  Interval iv_;
+  Real start_height_;
+  Real end_height_;
+  Real m_;
+  Real b_;
+
+  Building (Real start, Real start_height, Real end_height, Real end, Real max_slope);
+
+  Real height (Real x) const;
+  Real intersection (Building const &other) const;
+  void leading_part (Real chop, Real h);
+  bool obstructs (Building const &other) const;
 };
 
-void
-merge_skyline (vector<Skyline_entry> *a1, vector<Skyline_entry> const &a2,
-              Direction);
-void insert_extent_into_skyline (vector<Skyline_entry> *line, Box b, Axis line_axis,
-                                Direction d);
-vector<Skyline_entry>
-extents_to_skyline (vector<Box> const &extents, Axis a, Direction d);
-vector<Skyline_entry> empty_skyline (Direction d);
-void heighten_skyline (vector<Skyline_entry> *buildings, Real ground);
-Real
-skyline_meshing_distance (vector<Skyline_entry> const &buildings,
-                         vector<Skyline_entry> const &clouds);
-
-Real
-skyline_height (vector<Skyline_entry> const &buildings,
-               Real airplane, Direction sky_dir);
+class Skyline
+{
+private:
+  list<Building> buildings_;
+  Direction sky_;
+  Real max_slope_;
+  void internal_merge_skyline (list<Building>*, list<Building>*,
+                              list<Building> *const result);
+  void internal_build_skyline (list<Building>*,
+                              list<Building> *const result);
+  bool is_legal_skyline () const;
+
+public:
+  Skyline ();
+  Skyline (Direction sky);
+  Skyline (vector<Box> const &bldgs, Axis a, Direction sky);
+
+  void merge (Skyline const &);
+  void insert (Box const &, Axis);
+  void raise (Real);
+  Real distance (Skyline const &) const;
+  Real height (Real airplane) const;
+  Real max_height () const;
+  void set_minimum_height (Real height);
+  Stencil stencil ();
+};
 
 #endif /* SKYLINE_HH */
 
index 2fe740fddb954d6c5dc0befbec6ca6d2dc92c3ed..f10b9b750fb29578e9a1bea041c1c596aca77f83 100644 (file)
@@ -11,6 +11,7 @@
 #include "column-x-positions.hh"
 #include "spanner.hh"
 #include "grob-array.hh"
+#include "skyline.hh"
 
 /*
   If you keep following offset reference points, you will always end
@@ -21,6 +22,8 @@ class System : public Spanner
 {
   int rank_;
   Grob_array *all_elements_;
+  Drul_array<Skyline> skylines_;
+  void build_skylines ();
   void init_elements ();
   friend class Paper_score;    // ugh.
   Paper_score *pscore_;        // ugh.
index 1c82c4269efb65615db0504c97a102e77f1a19c9..3206e3203f07ccc29460dbbf1ed0da25df72d3c1 100644 (file)
@@ -13,7 +13,7 @@
 #include "lily-proto.hh"
 #include "tie-configuration.hh"
 
-void set_chord_outline (vector<Skyline_entry> *skyline,
+void set_chord_outline (Skyline *skyline,
                        vector<Item*> bounds,
                        Grob *common,
                        Direction d);
@@ -25,7 +25,7 @@ void final_shape_adjustment (Tie_configuration &conf,
                             Tie_formatting_problem const&,
                             Grob *staff_referencer);
 void
-set_chord_outlines (Drul_array< vector<Skyline_entry> > *skyline_drul,
+set_chord_outlines (Drul_array<Skyline> *skyline_drul,
                    vector<Grob*> ties,
                    Grob *common);
 
index 5d46129fe592778753e15cd497a3179a5e73e19f..7d48995d60798b7decd017e0064773aad912c9e2 100644 (file)
@@ -47,7 +47,7 @@ struct Tie_configuration_variation
   Tie_configuration_variation ();
 };
 
-typedef map < Tuple<int, 2>, vector<Skyline_entry> > Chord_outline_map;
+typedef map < Tuple<int, 2>, Skyline> Chord_outline_map;
 typedef map < Tuple<int, 2>, Box> Column_extent_map;
 class Tie_formatting_problem
 {
index 377d66b832e7b9fe829aea2a219f9636495f1c8a..9290ef93e523bf984170e95d43839281d823ec01 100644 (file)
@@ -91,6 +91,15 @@ Instrument_name_engraver::start_spanner ()
   text_spanner_->set_bound (LEFT, col);
   text_spanner_->set_property ("text", short_text_);
   text_spanner_->set_property ("long-text", long_text_);
+
+  /*
+    UGH, should handle this in Score_engraver.
+  */
+  Grob *system = unsmob_grob (get_property ("rootSystem"));
+  if (system)
+    Axis_group_interface::add_element (system, text_spanner_);
+  else
+    text_spanner_->programming_error ("can't find root system");
 }
 
 
@@ -130,16 +139,6 @@ Instrument_name_engraver::stop_spanner ()
 
   Pointer_group_interface::set_ordered (text_spanner_, ly_symbol2scm ("elements"), false);
 
-  System *system = get_root_system (text_spanner_);
-
-  /*
-    UGH, should handle this in Score_engraver.
-  */
-  if (system)
-    Axis_group_interface::add_element (system, text_spanner_);
-  else
-    text_spanner_->programming_error ("can't find root system");
-
   text_spanner_ = 0;
 }
 
index e1a0e9bffdc059fde75766d07b559dff3393bd2e..e932f342b731a2f2bd5fbdf4ddab27e5ec0ac18d 100644 (file)
@@ -114,15 +114,12 @@ gulp_file_to_string (string fn, bool must_exist, int size)
   return result;
 }
 
-extern "C" {
-  // maybe gdb 5.0 becomes quicker if it doesn't do fancy C++ typing?
-  void
-  ly_display_scm (SCM s)
-  {
-    scm_display (s, scm_current_output_port ());
-    scm_newline (scm_current_output_port ());
-  }
-};
+void
+ly_display_scm (void *s)
+{
+  scm_display ((SCM)s, scm_current_output_port ());
+  scm_newline (scm_current_output_port ());
+}
 
 string
 ly_scm2string (SCM str)
index 4e72121d122c8546a0c94f93ab6094bd31ece499..2eb6cec0bad9765e704859aeb7f01cfa317b4e9b 100644 (file)
@@ -641,3 +641,25 @@ main (int argc, char **argv)
   /* Only reachable if GUILE exits.  That is an error.  */
   return 1;
 }
+
+SCM atexit_list = SCM_EOL;
+
+LY_DEFINE (ly_atexit, "ly:atexit",
+          2, 0, 0, (SCM proc, SCM args),
+          "Just before exiting, call the procedure given. "
+"If this is called multiple times, the procedures are called "
+"in LIFO order.")
+{
+  atexit_list = scm_cons (scm_cons (proc, args), atexit_list);
+  scm_gc_protect_object (atexit_list);
+  return SCM_UNSPECIFIED;
+}
+
+LY_DEFINE (ly_do_atexit, "ly:do-atexit",
+          0, 0, 0, (),
+          "Call the atexit procedures.")
+{
+  for (SCM s = atexit_list; scm_is_pair (s); s = scm_cdr (s))
+    scm_apply_0 (scm_caar (s), scm_cdar (s));
+  return SCM_UNSPECIFIED;
+}
index be81de380bf49ec1d5fea180d445db17d7be7d49..02213e4c71a68d1cfdddc2276e7e1b35580f36bd 100644 (file)
@@ -21,6 +21,7 @@ using namespace std;
 /* Write midi as formatted ascii stream? */
 bool do_midi_debugging_global;
 bool use_object_keys;
+bool debug_skylines;
 
 /*
   Backwards compatibility.
@@ -89,6 +90,11 @@ void internal_set_option (SCM var, SCM val)
       strict_infinity_checking = to_boolean (val);
       val = scm_from_bool (to_boolean (val));
     }
+  else if (var == ly_symbol2scm ("debug-skylines"))
+    {
+      debug_skylines = to_boolean (val);
+      val = scm_from_bool (to_boolean (val));
+    }
 }
 
 ssize const HELP_INDENT = 30;
index f72ea5b2f6d5fcbf8c6cdf229d62077373b90c39..e52a6277d50adfeeb44b6f9369944f8c4a900909 100644 (file)
-/*
-  skyline.cc -- implement Skyline_entry and funcs.
+/* skyline.cc -- implement the Skyline class
 
-  source file of the GNU LilyPond music typesetter
-
-  (c) 2002--2006 Han-Wen Nienhuys <hanwen@xs4all.nl>
+   source file of the GNU LilyPond music typesetter
+   (c) 2006 Joe Neeman <joeneeman@gmail.com>
 */
 
 #include "skyline.hh"
 
-/*
-  A skyline is a shape of the form:
-
-
-  *                  ----
-  *                  |  |
-  *         ---------|  |
-  *         |           |
-  *         |           |
-  *         |          |______
-  * --------|                |___
-  *
-
-  This file deals with building such skyline structure, and computing
-  the minimum distance between two opposing skylines.
-
-  Invariants for a skyline:
-
-  skyline[...].width_ forms a partition of the real interval, where
-  the segments are adjacent, and ascending. Hence we have
-
-  skyline.back ().width_[RIGHT] = inf
-  skyline[0].width_[LEFT] = -inf
+#include "line-interface.hh"
+
+/* A skyline is a sequence of non-overlapping buildings: something like
+   this:
+                   _______
+                  /       \                                ________
+                 /         \                      ________/        \
+        /\      /           \                    /                  \
+       /  -----/              \                 /                    \
+      /                         \              /                      \
+     /                            ------------/                        ----
+   --
+   Each building has a starting position, and ending position, a starting
+   height and an ending height.
+
+   The following invariants are observed:
+    - the start of the first building is at -infinity
+    - the end of the last building is at infinity
+    - if a building has infinite length (ie. the first and last buildings),
+      then its starting height and ending height are equal
+    - the end of one building is the same as the beginning of the next
+      building
+
+   We also allow skylines to point down (the structure is exactly the same,
+   but we think of the part above the line as being filled with mass and the
+   part below as being empty). ::distance finds the minimum distance between
+   an UP skyline and a DOWN skyline.
+
+   Note that we store DOWN skylines upside-down. That is, in order to compare
+   a DOWN skyline with an UP skyline, we need to flip the DOWN skyline first.
+   This means that the merging routine doesn't need to be aware of direction,
+   but the distance routine does.
 */
 
-const Real EPS = 1e-12;
-
-/*
-  TODO: avoid unnecessary fragmentation.
+#define EPS 1e-10
 
-  This is O (n^2), searching and insertion.  Could be O (n log n) with
-  binsearch.
-*/
-void
-insert_extent_into_skyline (vector<Skyline_entry> *line, Box b, Axis line_axis,
-                           Direction d)
+static inline bool
+equal (Real x, Real y)
 {
-  Interval extent = b[line_axis];
-  if (extent.is_empty ())
-    return;
+  return abs (x - y) < EPS || (isinf (x) && isinf (y) && ((x > 0) == (y > 0)));
+}
 
-  Real stick_out = b[other_axis (line_axis)][d];
+bool
+Skyline::is_legal_skyline () const
+{
+  list<Building>::const_iterator i;
+  Real last_x = -infinity_f;
+  Real last_h = -infinity_f;
+  for (i = buildings_.begin (); i != buildings_.end (); i++)
+    {
+      if (i->iv_[LEFT] != last_x)
+       return false;
+      if (i != buildings_.begin () && !equal (i->start_height_, last_h))
+       return false;
+      last_x = i->iv_[RIGHT];
+      last_h = i->end_height_;
+    }
+  return last_x == infinity_f;
+}
 
-  /*
-    Intersect each segment of LINE with EXTENT, and if non-empty, insert relevant segments.
-  */
-  for (vsize i = line->size (); i--;)
+Building::Building (Real start, Real start_height, Real end_height, Real end, Real max_slope)
+  : iv_ (start, end)
+{
+  start_height_ = start_height;
+  end_height_ = end_height;
+
+  if (isinf (start))
+    assert (isinf (start_height) || start_height == end_height);
+  if (isinf (end))
+    assert (isinf (end_height) || start_height == end_height);
+
+  m_ = (end_height - start_height) / (end - start);
+  if (start_height == end_height)
+    m_ = 0;
+  if (isinf (m_) || isnan (m_))
+    m_ = max_slope * (start_height < end_height ? 1 : -1);
+  assert (abs (m_) <= max_slope);
+
+  if (isinf (start))
     {
-      Interval w = line->at (i).width_;
-      w.intersect (extent);
+      if (isinf (end))
+       b_ = start_height;
+      else
+       b_ = end_height - m_*end;
+    }
+  else
+    b_ = start_height - m_*start;
+}
 
-      if (extent[LEFT] >= w[RIGHT])
-       break;
+Real 
+Building::height (Real x) const
+{
+  if (isinf (x))
+    return (x > 0) ? end_height_ : start_height_;
+  return m_*x + b_;
+}
 
-      Real my_height = line->at (i).height_;
+Real
+Building::intersection (Building const &other) const
+{
+  return (b_ - other.b_) / (other.m_ - m_);
+}
 
-      if (!w.is_empty ()
-         && w.length () > EPS
-         && d * (my_height - stick_out) < 0)
-       {
-         Interval e1 (line->at (i).width_[LEFT], extent[LEFT]);
-         Interval e3 (extent[RIGHT], line->at (i).width_[RIGHT]);
+void
+Building::leading_part (Real chop, Real h)
+{
+  assert (chop > iv_[LEFT] && chop <= iv_[RIGHT] && !equal (chop, iv_[LEFT]));
+  assert (equal (h, height (chop)));
+  iv_[RIGHT] = chop;
+  end_height_ = h;
+}
 
-         if (!e3.is_empty () && e3.length () > EPS)
-           line->insert (line->begin () + i + 1, Skyline_entry (e3, my_height));
+static void
+skyline_trailing_part (list<Building> *sky, Real x)
+{
+  if (equal (x, sky->front ().iv_[RIGHT]))
+    sky->pop_front ();
+  else
+    assert (x < sky->front ().iv_[RIGHT]);
 
-         line->at (i).height_ = stick_out;
-         line->at (i).width_ = w;
-         if (!e1.is_empty () && e1.length () > EPS)
-           line->insert (line->begin () + i, Skyline_entry (e1, my_height));
-       }
+  if (!sky->empty ())
+    {
+      sky->front ().iv_[LEFT] = x;
+      sky->front ().start_height_ = sky->front ().height (x);
     }
 }
 
+bool
+Building::obstructs (Building const &other) const
+{
+  if (equal (intersection (other), iv_[LEFT]) || equal (start_height_, other.start_height_))
+    return m_ > other.m_ || (m_ == other.m_ && b_ > other.b_);
+  return start_height_ > other.start_height_;
+}
+
 void
-merge_skyline (vector<Skyline_entry> *a1,
-              vector<Skyline_entry> const &a2,
-              Direction dir)
+Skyline::internal_merge_skyline (list<Building> *s1, list<Building> *s2,
+                                list<Building> *const result)
 {
-  for (vsize i = 0; i < a2.size (); i++)
+  while (!s1->empty ())
     {
-      Box b;
-      b[X_AXIS] = a2[i].width_;
-      b[Y_AXIS][dir] = a2[i].height_;
-      b[Y_AXIS][-dir] = dir * infinity_f;
-
-      insert_extent_into_skyline (a1, b, X_AXIS, dir);
+      if (s2->front ().obstructs (s1->front ()))
+       swap (s1, s2);
+
+      Building b = s1->front ();
+      while (s2->front ().iv_[RIGHT] < b.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;
+      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);
+
+      b.leading_part (end, height);
+      result->push_front (b);
+
+      skyline_trailing_part (s1, end);
+      if (!s1->empty ())
+       s1->front ().start_height_ = height;
+      skyline_trailing_part (s2, end);
     }
+  result->reverse ();
 }
 
-vector<Skyline_entry>
-empty_skyline (Direction d)
+static void
+empty_skyline (list<Building> *const ret)
 {
-  vector<Skyline_entry> skyline;
+  ret->push_front (Building (-infinity_f, -infinity_f, -infinity_f, infinity_f, 0));
+}
 
-  Interval i;
-  i.set_empty ();
-  i.swap ();
-  Skyline_entry e;
-  e.width_ = i;
-  e.height_ = -d * infinity_f;
-  skyline.push_back (e);
-  return skyline;
+static void
+single_skyline (Building const &b, list<Building> *const ret, Real max_slope)
+{
+  if (!isinf (b.iv_[RIGHT]))
+    ret->push_front (Building (b.iv_[RIGHT], b.end_height_, -infinity_f, infinity_f, max_slope));
+  ret->push_front (b);
+  if (!isinf (b.iv_[LEFT]))
+    ret->push_front (Building (-infinity_f, -infinity_f, b.start_height_, b.iv_[LEFT], max_slope));
 }
 
-vector<Skyline_entry>
-extents_to_skyline (vector<Box> const &extents, Axis a, Direction d)
+void
+Skyline::internal_build_skyline (list<Building> *buildings, list<Building> *const result)
 {
+  vsize size = buildings->size ();
 
-  vector<Skyline_entry> skyline = empty_skyline (d);
+  if (size == 0)
+    {
+      empty_skyline (result);
+      return;
+    }
+  else if (size == 1)
+    {
+      single_skyline (buildings->front (), result, max_slope_);
+      return;
+    }
 
-  /*
-    This makes a cubic algorithm (array  insertion is O (n),
-    searching the array dumbly is O (n), and for n items, we get O (n^3).)
+  list<Building> right_half;
+  list<Building>::iterator i = buildings->begin ();
 
-    We could do a lot better (n log (n), using a balanced tree) but
-    that seems overkill for now.
-  */
-  for (vsize j = extents.size (); j--;)
-    insert_extent_into_skyline (&skyline, extents[j], a, d);
+  for (vsize s = 0; s < size/2; s++)
+    i++;
+  right_half.splice (right_half.end (), *buildings, i, buildings->end ());
 
-  return skyline;
+  list<Building> right;
+  list<Building> left;
+  internal_build_skyline (&right_half, &right);
+  internal_build_skyline (buildings, &left);
+  internal_merge_skyline (&right, &left, result);
 }
 
-/*
-  minimum distance that can be achieved between baselines. "Clouds" is
-  a skyline pointing down.
+Skyline::Skyline ()
+{
+  max_slope_ = 2;
+  sky_ = UP;
+  empty_skyline (&buildings_);
+}
 
-  This is an O (n) algorithm.
-*/
-Real
-skyline_meshing_distance (vector<Skyline_entry> const &buildings,
-                         vector<Skyline_entry> const &clouds)
+Skyline::Skyline (Direction sky)
 {
-  int i = buildings.size () -1;
-  int j = clouds.size () -1;
+  max_slope_ = 2;
+  sky_ = sky;
+  empty_skyline (&buildings_);
+}
 
-  Real distance = -infinity_f;
+Skyline::Skyline (vector<Box> const &boxes, Axis a, Direction sky)
+{
+  list<Building> bldgs;
+  sky_ = sky;
+  max_slope_ = 2;
 
-  while (i > 0 || j > 0)
+  for (vsize i = 0; i < boxes.size (); i++)
     {
-      Interval w = buildings[i].width_;
-      w.intersect (clouds[j].width_);
+      Interval iv = boxes[i][a];
+      Real height = sky * boxes[i][other_axis (a)][sky];
+      if (!iv.is_empty () && !isinf (height) && !equal (iv[LEFT], iv[RIGHT]))
+       bldgs.push_front (Building (iv[LEFT], height, height, iv[RIGHT], max_slope_));
+    }
+  internal_build_skyline (&bldgs, &buildings_);
+  assert (is_legal_skyline ());
+}
 
-      if (!w.is_empty ())
-       distance = max (distance, (buildings[i].height_ - clouds[j].height_));
+void
+Skyline::merge (Skyline const &other)
+{
+  assert (sky_ == other.sky_);
 
-      if (i > 0 && buildings[i].width_[LEFT] >= clouds[j].width_[LEFT])
-       i--;
-      else if (j > 0 && buildings[i].width_[LEFT] <= clouds[j].width_[LEFT])
-       j--;
-    }
+  list<Building> other_bld (other.buildings_);
+  list<Building> my_bld;
+  my_bld.splice (my_bld.begin (), buildings_);
+  internal_merge_skyline (&other_bld, &my_bld, &buildings_);
+  assert (is_legal_skyline ());
+}
 
-  return distance;
+void
+Skyline::insert (Box const &b, Axis a)
+{
+  list<Building> other_bld;
+  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 ());
 }
 
-Skyline_entry::Skyline_entry ()
+void
+Skyline::raise (Real r)
 {
-  height_ = 0.0;
+  list<Building>::iterator end = buildings_.end ();
+  for (list<Building>::iterator i = buildings_.begin (); i != end; i++)
+    {
+      i->start_height_ += sky_ * r;
+      i->end_height_ += sky_ * r;
+      i->b_ += sky_ * r;
+    }
+  assert (is_legal_skyline ());
 }
 
-Skyline_entry::Skyline_entry (Interval i, Real r)
+Real
+Skyline::distance (Skyline const &other) const
 {
-  width_ = i;
-  height_ = r;
+  assert (sky_ == -other.sky_);
+  list<Building>::const_iterator i = buildings_.begin ();
+  list<Building>::const_iterator j = other.buildings_.begin ();
+
+  Real dist = -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])
+       i++;
+      else
+       j++;
+    }
+  return dist;
 }
 
-void
-heighten_skyline (vector<Skyline_entry> *buildings, Real ground)
+Real
+Skyline::height (Real airplane) const
 {
-  for (vsize i = 0; i < buildings->size (); i++)
-    buildings->at (i).height_ += ground;
+  assert (!isinf (airplane));
+
+  list<Building>::const_iterator i;
+  for (i = buildings_.begin (); i != buildings_.end (); i++)
+    {
+      if (i->iv_[RIGHT] >= airplane)
+       return sky_ * i->height (airplane);
+    }
+  assert (0);
+  return 0;
 }
 
 Real
-skyline_height (vector<Skyline_entry> const &buildings,
-               Real airplane,
-               Direction sky_dir)
+Skyline::max_height () const
 {
-  Real h = - sky_dir * infinity_f;
+  Skyline s (-sky_);
+  s.set_minimum_height (0);
+  return sky_ * distance (s);
+}
 
-  /*
-    Ugh! linear, should be O(log n).
-   */
-  for (vsize i = 0; i < buildings.size (); i++)
-    if (buildings[i].width_.contains (airplane))
-      h = sky_dir * max (sky_dir * h,
-                        sky_dir * buildings[i].height_);
-  
-  return h;
+void
+Skyline::set_minimum_height (Real h)
+{
+  Skyline s (sky_);
+  s.buildings_.front ().start_height_ = h*sky_;
+  s.buildings_.front ().end_height_ = h*sky_;
+  s.buildings_.front ().b_ = h*sky_;
+  merge (s);
 }
 
+Stencil
+Skyline::stencil ()
+{
+  Stencil ret;
+  for (list<Building>::iterator i = buildings_.begin (); i != buildings_.end (); i++)
+    {
+      if (!isinf (i->iv_.length ()))
+       {
+         Stencil line = Line_interface::make_line (0.1,
+                                                   Offset (i->iv_[LEFT], sky_*i->start_height_),
+                                                   Offset (i->iv_[RIGHT], sky_*i->end_height_));
+         ret.add_stencil (line);
+       }
+    }
+  return ret;
+}
index 0649849b2111170163e66462afaca0a5fe00cc36..7c1828cabde793c1c963595846bdb66da598811e 100644 (file)
@@ -24,6 +24,8 @@
 #include "tweak-registration.hh"
 #include "warn.hh"
 
+extern bool debug_skylines;
+
 System::System (System const &src, int count)
   : Spanner (src, count)
 {
@@ -186,6 +188,13 @@ System::get_paper_systems ()
       System *system = dynamic_cast<System *> (broken_intos_[i]);
 
       system->post_processing ();
+      system->build_skylines ();
+      if (i > 0)
+       {
+         System *prev = dynamic_cast<System*> (broken_intos_[i-1]);
+         Real r = prev->skylines_[DOWN].distance (system->skylines_[UP]);
+         system->set_property ("skyline-distance", scm_from_double (r));
+       }
       scm_vector_set_x (lines, scm_from_int (i),
                        system->get_paper_system ());
 
@@ -391,6 +400,11 @@ System::get_paper_system ()
   Stencil sys_stencil (Box (x, y),
                       scm_cons (ly_symbol2scm ("combine-stencil"),
                                 exprs));
+  if (debug_skylines)
+    {
+      sys_stencil.add_stencil (skylines_[UP].stencil ().in_color (255, 0, 0));
+      sys_stencil.add_stencil (skylines_[DOWN].stencil ().in_color (0, 255, 0));
+    }
 
   Grob *left_bound = this->get_bound (LEFT);
   SCM prop_init = left_bound->get_property ("line-break-system-details");
@@ -399,6 +413,7 @@ System::get_paper_system ()
 
   /* information that the page breaker might need */
   Grob *right_bound = this->get_bound (RIGHT);
+  pl->set_property ("skyline-distance", get_property ("skyline-distance"));
   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"));
@@ -499,6 +514,25 @@ 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));
+    }
+
+  skylines_[UP] = Skyline (boxes, X_AXIS, UP);
+  skylines_[DOWN] = Skyline (boxes, X_AXIS, DOWN);
+}
 
 
 ADD_INTERFACE (System, "system-interface",
@@ -510,4 +544,5 @@ ADD_INTERFACE (System, "system-interface",
               "columns "
               "pure-Y-extent "
               "spaceable-staves "
+              "skyline-distance "
               )
index 4dada25d220116b68dfc8f6a70b8a7e962a53a1e..0e29d3ca50a1f028c7c1f87270e333bf31538208 100644 (file)
@@ -51,7 +51,7 @@ Tie_formatting_problem::get_attachment (Real y, Drul_array<int> columns) const
       if (i == chord_outlines_.end ())
        programming_error ("Can't find chord outline");
       else
-       attachments[d] = skyline_height ((*i).second, y, -d);
+       attachments[d] = i->second.height (y);
     }
   while (flip (&d) != LEFT);
   
@@ -115,28 +115,6 @@ Tie_formatting_problem::set_column_chord_outline (vector<Item*> bounds,
     }
 
   Tuple2<int> key (column_rank, int (dir));
-  
-  chord_outlines_[key] = empty_skyline (-dir);
-      
-  if (bounds[0]->break_status_dir ())
-    {
-      Real x = robust_relative_extent (bounds[0],  x_refpoint_, X_AXIS)[-dir];
-      chord_outlines_[key].at (0).height_ = x; 
-    }
-  else
-    {
-      Interval x;
-      for (vsize j = 0; j < head_boxes.size (); j++)
-       {
-         x.unite (head_boxes[j][X_AXIS]);
-       }
-      
-      chord_outlines_[key].at (0).height_ = x[dir];
-    }
-      
-  for (vsize i = 0; i < boxes.size (); i++)
-    insert_extent_into_skyline (&chord_outlines_[key]  ,
-                               boxes[i], Y_AXIS, -dir);
 
   if (stem
       && !Stem::is_invisible (stem))
@@ -150,8 +128,8 @@ Tie_formatting_problem::set_column_chord_outline (vector<Item*> bounds,
       Direction stemdir = get_grob_direction (stem);
       y.add_point (Stem::head_positions (stem)[-stemdir]
                   * staff_space * .5);
-         
-      insert_extent_into_skyline (&chord_outlines_[key], Box (x,y), Y_AXIS, -dir);
+
+      boxes.push_back (Box (x, y));
 
       stem_extents_[key].unite (Box (x,y));
 
@@ -159,8 +137,7 @@ Tie_formatting_problem::set_column_chord_outline (vector<Item*> bounds,
        {
          Box flag_box = Stem::get_translated_flag (stem).extent_box ();
          flag_box.translate( Offset (x[RIGHT], X_AXIS));
-         insert_extent_into_skyline (&chord_outlines_[key], flag_box,
-                                     Y_AXIS, -dir);
+         boxes.push_back (flag_box);
        }
     }
   else if (stem)
@@ -176,10 +153,8 @@ Tie_formatting_problem::set_column_chord_outline (vector<Item*> bounds,
       Interval y_ext;
       for (vsize j = 0; j < head_boxes.size (); j++)
        y_ext.unite (head_boxes[j][Y_AXIS]);
-         
-      insert_extent_into_skyline (&chord_outlines_[key],
-                                 Box (x_ext, y_ext),
-                                 Y_AXIS, -dir);
+
+      boxes.push_back (Box (x_ext, y_ext));
     }
   
   Direction updowndir = DOWN;
@@ -197,12 +172,27 @@ Tie_formatting_problem::set_column_chord_outline (vector<Item*> bounds,
        }
 
       if (!x.is_empty ())
-       insert_extent_into_skyline (&chord_outlines_[key],
-                                   Box (x,y),
-                                   Y_AXIS, -dir);
+       boxes.push_back (Box (x, y));
     }
   while (flip (&updowndir) != DOWN);
   
+  chord_outlines_[key] = Skyline (boxes, Y_AXIS, -dir);
+  if (bounds[0]->break_status_dir ())
+    {
+      Real x = robust_relative_extent (bounds[0],  x_refpoint_, X_AXIS)[-dir];
+      chord_outlines_[key].set_minimum_height (x);
+    }
+  else
+    {
+      Interval x;
+      for (vsize j = 0; j < head_boxes.size (); j++)
+       {
+         x.unite (head_boxes[j][X_AXIS]);
+       }
+      
+      chord_outlines_[key].set_minimum_height (x[dir]);
+    }
+
   head_extents_[key].set_empty ();
   for (vsize i = 0; i < head_boxes.size (); i++)
     {
@@ -344,22 +334,12 @@ Tie_formatting_problem::from_semi_ties (vector<Grob*> const &semi_ties, Directio
 
   set_chord_outline (heads, head_dir);
 
-  Real extremal = head_dir * infinity_f;   
-
   Tuple2<int> head_key (column_rank, head_dir);
   Tuple2<int> open_key (column_rank, -head_dir);
-  
-  for (vsize i = 0; i < chord_outlines_[head_key].size (); i++)
-    {
-      extremal = head_dir * min (head_dir * extremal,
-                                head_dir * chord_outlines_[head_key][i].height_);
-    }
+  Real extremal = chord_outlines_[head_key].max_height ();
 
-  Skyline_entry right_entry;
-  right_entry.width_.set_full ();
-  right_entry.height_ = extremal - head_dir * 1.5;
-  
-  chord_outlines_[open_key].push_back (right_entry);
+  chord_outlines_[open_key] = Skyline (head_dir);
+  chord_outlines_[open_key].set_minimum_height (extremal - head_dir * 1.5);
 }
 
 
index dddcef9aeec4dd276a1cf0eca9eab0e134fbebde..38fe501282a58d85ec9f9ffb1667a473af1b988c 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
@@ -549,6 +552,9 @@ than a whole rest.")
      
 
      (spaceable-staves ,ly:grob-array? "Objects to be spaced during page layout.")
+     (skyline-distance ,number? "The distance between this staff and the next one, as determined by a skyline algorithm.")
+     (skyline-spacing ,boolean? "When true, this axis-group will vertically space its children
+using a skyline algorithm.")
 
      
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
index bd5dee7706c217a87301acfbbfd1b71a74acb26c..5e2dd4d86c14ea0572aadc11d7d5ae6a9e2f28b1 100644 (file)
        (axes . (0 1))
        (X-extent . ,ly:axis-group-interface::width)
        (Y-extent . ,ly:axis-group-interface::height)
+       (skyline-spacing . #t)
        (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)
+       (skyline-spacing . #t)
        (meta . ((class . Spanner)
                 (interfaces . (axis-group-interface
                                hara-kiri-group-interface
diff --git a/scm/graphviz.scm b/scm/graphviz.scm
new file mode 100644 (file)
index 0000000..d3a858f
--- /dev/null
@@ -0,0 +1,35 @@
+(define-module (scm graphviz)
+  #:use-module (lily)
+  #:export (make-graph add-node add-edge))
+
+(define (make-graph filename)
+  (let ((empty-graph (list->vector (list filename '() '() '()))))
+    (ly:atexit write-graph (list empty-graph))
+    empty-graph))
+
+(define (filename g) (vector-ref g 0))
+(define (nodes g) (vector-ref g 1))
+(define (edges g) (vector-ref g 2))
+(define (clusters g) (vector-ref g 3))
+
+(define (add-node graph label)
+  (let ((ns (nodes graph)))
+    (vector-set! graph 1 (cons `(,(length ns) . ,label) ns))
+    (length ns)))
+
+(define (add-edge graph node1 node2)
+  (vector-set! graph 2 (cons `(,node1 . ,node2) (edges graph))))
+
+(define (write-graph graph)
+  (let ((out (open-file (filename graph) "w"))
+       (ns (nodes graph))
+       (es (edges graph))
+       (cc (clusters graph)))
+    (ly:message (format "writing graph ~s..." (filename graph)))
+    (display "digraph G {\nrankdir=\"LR\"\nnode [shape=rectangle]\n" out)
+    (map (lambda (n) (display (format "~a [label=\"~a\"]\n" (car n) (cdr n)) out))
+        ns)
+    (map (lambda (e) (display (format "~a -> ~a\n" (car e) (cdr e)) out))
+        es)
+    (display "}" out)))
+  
\ No newline at end of file
index e370a171323254050179f6e777eea2bece37b859..090ad06b7bf6d98eb4c4c25b871c5330412a75ce 100644 (file)
   "Minimum distance between `line' reference position and `next-line'
  reference position. If next-line is #f, return #f."
   (and next-line
-       (max 0 (- (+ (interval-end (paper-system-extent next-line Y))
-                   (if ignore-padding 0 (line-next-padding line next-line layout)))
-                (interval-start (paper-system-extent line Y))))))
+       (let ((non-skyline-distance (- (interval-end (paper-system-extent next-line Y))
+                                     (interval-start (paper-system-extent line Y)))))
+        (max 0 (+ (ly:prob-property next-line 'skyline-distance non-skyline-distance)
+                  (if ignore-padding 0 (line-next-padding line next-line layout)))))))
 
 (define (line-ideal-distance line next-line layout ignore-padding)
   "Ideal distance between `line' reference position and `next-line'
index 2241c850474b1edca466fa9d743d6c5c917d5b72..f3767ca9f5fb04e8231a2387ab2cf405272cfc70 100644 (file)
@@ -26,6 +26,7 @@
              (debug-lexer #f "debug the flex lexer")
              (debug-midi #f "generate human readable MIDI")
              (debug-parser #f "debug the bison parser")
+             (debug-skylines #f "debug skylines")
              (delete-intermediate-files #f
                                         "delete unusable PostScript files")
              (dump-signatures #f "dump output signatures of each system")
@@ -421,6 +422,7 @@ The syntax is the same as `define*-public'."
          (ly:error (_ "failed files: ~S") (string-join failed))
          (exit 1))
        (begin
+         (ly:do-atexit)
          ;; HACK: be sure to exit with single newline
          (ly:message "")
          (exit 0)))))