]> git.donarmstrong.com Git - lilypond.git/blobdiff - lily/skyline.cc
Imported Upstream version 2.14.2
[lilypond.git] / lily / skyline.cc
index a3047a98bbcefffe4c071df3fa49618ee9ddc453..fe30291f78812d90aa07494414972639241aaef4 100644 (file)
@@ -1,8 +1,20 @@
-/* skyline.cc -- implement the Skyline class
+/*
+  This file is part of LilyPond, the GNU music typesetter.
+
+  Copyright (C) 2006--2011 Joe Neeman <joeneeman@gmail.com>
+
+  LilyPond is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  LilyPond is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
 
-   source file of the GNU LilyPond music typesetter
-   (c) 2006--2009 Joe Neeman <joeneeman@gmail.com>
+  You should have received a copy of the GNU General Public License
+  along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "skyline.hh"
@@ -107,7 +119,7 @@ Building::precompute (Real start, Real start_height, Real end_height, Real end)
     y_intercept_ = start_height - slope_ * start;
 }
 
-Real 
+Real
 Building::height (Real x) const
 {
   return isinf (x) ? y_intercept_ : slope_*x + y_intercept_;
@@ -227,6 +239,10 @@ empty_skyline (list<Building> *const ret)
   ret->push_front (Building (-infinity_f, -infinity_f, -infinity_f, infinity_f));
 }
 
+/*
+  Given Building 'b' with starting wall location 'start', extend each side
+  with a sloped roofline of width 'horizon_padding'; put the skyline in 'ret'
+*/
 static void
 single_skyline (Building b, Real start, Real horizon_padding, list<Building> *const ret)
 {
@@ -236,7 +252,7 @@ single_skyline (Building b, Real start, Real horizon_padding, list<Building> *co
                               -infinity_f, infinity_f));
   if (sloped_neighbours)
     ret->push_front (b.sloped_neighbour (start, horizon_padding, RIGHT));
-  
+
   if (b.end_ > start + EPS)
     ret->push_front (b);
 
@@ -318,7 +334,8 @@ Skyline::internal_build_skyline (list<Box> *boxes, Real horizon_padding, Axis ho
     {
       list<Building> result;
       single_skyline (Building (boxes->front (), horizon_padding, horizon_axis, sky),
-                     boxes->front ()[horizon_axis][LEFT], horizon_padding, &result);
+                     boxes->front ()[horizon_axis][LEFT] - horizon_padding,
+                     horizon_padding, &result);
       return result;
     }
 
@@ -355,7 +372,7 @@ Skyline::Skyline ()
 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++)
@@ -370,6 +387,37 @@ Skyline::Skyline (Direction sky)
   empty_skyline (&buildings_);
 }
 
+/*
+  build padded skyline from an existing skyline with padding
+  added to it.
+*/
+
+Skyline::Skyline (Skyline const &src, Real horizon_padding, Axis a)
+{
+  /*
+     We extract boxes from the skyline, then build a new skyline from
+     the boxes.
+     A box is created for every horizontal portion of the skyline
+     Because skylines are defined positive, and then inverted if they
+     are to be down-facing, we create the new skyline in the UP
+     direction, then give it the down direction if needed.
+  */
+  Real start = -infinity_f;
+  list<Box> boxes;
+
+  // establish a baseline box
+  boxes.push_back (Box (Interval (-infinity_f, infinity_f),
+                       Interval (0, 0)));
+  list<Building>::const_iterator end = src.buildings_.end ();
+  for (list<Building>::const_iterator i = src.buildings_.begin (); i != end; start=i->end_, i++ )
+    if ((i->slope_ == 0) && !isinf (i->y_intercept_))
+      boxes.push_back (Box (Interval (start, i->end_),
+                           Interval (-infinity_f , i->y_intercept_)));
+  buildings_ = internal_build_skyline (&boxes, horizon_padding, X_AXIS, UP);
+  sky_ = src.sky_;
+}
+
+
 /*
   build skyline from a set of boxes. If horizon_padding > 0, expand all the boxes
   by that amount and add 45-degree sloped boxes to the edges of each box (of
@@ -392,7 +440,7 @@ Skyline::Skyline (vector<Box> const &boxes, Real horizon_padding, Axis horizon_a
       if (iv.length () > EPS && !boxes[i][vert_axis].is_empty ())
        filtered_boxes.push_front (boxes[i]);
     }
-  
+
   buildings_ = internal_build_skyline (&filtered_boxes, horizon_padding, horizon_axis, sky);
 }
 
@@ -400,7 +448,8 @@ Skyline::Skyline (Box const &b, Real horizon_padding, Axis horizon_axis, Directi
 {
   sky_ = sky;
   Building front (b, horizon_padding, horizon_axis, sky);
-  single_skyline (front, b[horizon_axis][LEFT], horizon_padding, &buildings_);
+  single_skyline (front, b[horizon_axis][LEFT] - horizon_padding,
+                 horizon_padding, &buildings_);
 }
 
 void
@@ -434,7 +483,8 @@ Skyline::insert (Box const &b, Real horizon_padding, Axis a)
     return;
 
   my_bld.splice (my_bld.begin (), buildings_);
-  single_skyline (Building (b, horizon_padding, a, sky_), b[a][LEFT], horizon_padding, &other_bld);
+  single_skyline (Building (b, horizon_padding, a, sky_), b[a][LEFT] - horizon_padding,
+                 horizon_padding, &other_bld);
   internal_merge_skyline (&other_bld, &my_bld, &buildings_);
 }
 
@@ -458,15 +508,31 @@ Skyline::shift (Real s)
 }
 
 Real
-Skyline::distance (Skyline const &other) const
+Skyline::distance (Skyline const &other, Real horizon_padding) const
 {
   assert (sky_ == -other.sky_);
-  list<Building>::const_iterator i = buildings_.begin ();
-  list<Building>::const_iterator j = other.buildings_.begin ();
+
+  Skyline const *padded_this = this;
+  Skyline const *padded_other = &other;
+
+  /*
+    For systems, padding is not added at creation time.  Padding is
+    added to AxisGroup objects when outside-staff objects are added.
+    Thus, when we want to place systems with horizontal padding,
+    we do it at distance calculation time.
+  */
+  if (horizon_padding != 0.0)
+    {
+      padded_this = new Skyline (*padded_this, horizon_padding, X_AXIS);
+      padded_other = new Skyline (*padded_other, horizon_padding, X_AXIS);
+    }
+
+  list<Building>::const_iterator i = padded_this->buildings_.begin ();
+  list<Building>::const_iterator j = padded_other->buildings_.begin ();
 
   Real dist = -infinity_f;
   Real start = -infinity_f;
-  while (i != buildings_.end () && j != other.buildings_.end ())
+  while (i != padded_this->buildings_.end () && j != padded_other->buildings_.end ())
     {
       Real end = min (i->end_, j->end_);
       Real start_dist = i->height (start) + j->height (start);
@@ -542,6 +608,12 @@ Skyline::is_empty () const
   return b.end_ == infinity_f && b.y_intercept_ == -infinity_f;
 }
 
+void
+Skyline::clear ()
+{
+  buildings_.clear ();
+  empty_skyline (&buildings_);
+}
 
 /****************************************************************/