X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Fskyline.cc;h=fe30291f78812d90aa07494414972639241aaef4;hb=71cea6af77bf3d639dcfd8ad09fd235aab22c5f7;hp=8c47df70b8f1cbc079c947b1a0bc0379e5364aab;hpb=a0df7dcd3b849dd7284f9325704584d916b8f485;p=lilypond.git diff --git a/lily/skyline.cc b/lily/skyline.cc index 8c47df70b8..fe30291f78 100644 --- a/lily/skyline.cc +++ b/lily/skyline.cc @@ -1,12 +1,25 @@ -/* skyline.cc -- implement the Skyline class +/* + This file is part of LilyPond, the GNU music typesetter. + + Copyright (C) 2006--2011 Joe Neeman + + 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. - source file of the GNU LilyPond music typesetter - - (c) 2006--2007 Joe Neeman + LilyPond is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with LilyPond. If not, see . */ #include "skyline.hh" #include +#include #include "ly-smobs.icc" @@ -59,6 +72,16 @@ Skyline::print () const print_buildings (buildings_); } +void +Skyline::print_points () const +{ + vector ps (to_points (X_AXIS)); + + for (vsize i = 0; i < ps.size (); i++) + printf ("(%f,%f)%s" , ps[i][X_AXIS], ps[i][Y_AXIS], + (i%2)==1 ? "\n" : " "); +} + Building::Building (Real start, Real start_height, Real end_height, Real end) { if (isinf (start) || isinf (end)) @@ -96,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_; @@ -166,7 +189,7 @@ Building::conceals (Building const &other, Real x) const /* their slopes were not equal, so there is an intersection point */ Real i = intersection_x (other); - return (i < x && slope_ > other.slope_) + return (i <= x && slope_ > other.slope_) || (i > x && slope_ < other.slope_); } @@ -174,6 +197,12 @@ void Skyline::internal_merge_skyline (list *s1, list *s2, list *const result) { + if (s1->empty () || s2->empty ()) + { + programming_error ("tried to merge an empty skyline"); + return; + } + Real x = -infinity_f; while (!s1->empty ()) { @@ -210,6 +239,10 @@ empty_skyline (list *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 *const ret) { @@ -219,7 +252,7 @@ single_skyline (Building b, Real start, Real horizon_padding, list *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); @@ -250,7 +283,7 @@ non_overlapping_skyline (list *const boxes, Real horizon_padding, Axis hori } if (iv[LEFT] - horizon_padding > last_end + EPS) - result.push_front (Building (last_end, -infinity_f, -infinity_f, iv[LEFT] - horizon_padding)); + result.push_front (Building (last_end, -infinity_f, -infinity_f, iv[LEFT] - 2*horizon_padding)); Building b (*i, horizon_padding, horizon_axis, sky); bool sloped_neighbours = horizon_padding > 0 && !isinf (iv.length ()); @@ -301,7 +334,8 @@ Skyline::internal_build_skyline (list *boxes, Real horizon_padding, Axis ho { list result; single_skyline (Building (boxes->front (), horizon_padding, horizon_axis, sky), - boxes->front ()[horizon_axis][LEFT], horizon_axis, &result); + boxes->front ()[horizon_axis][LEFT] - horizon_padding, + horizon_padding, &result); return result; } @@ -332,13 +366,13 @@ Skyline::internal_build_skyline (list *boxes, Real horizon_padding, Axis ho Skyline::Skyline () { sky_ = UP; - empty_skyline (&buildings_); + empty_skyline (&buildings_); } Skyline::Skyline (Skyline const &src) { sky_ = src.sky_; - + /* doesn't a list's copy constructor do this? -- jneem */ for (list::const_iterator i = src.buildings_.begin (); i != src.buildings_.end (); i++) @@ -353,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 boxes; + + // establish a baseline box + boxes.push_back (Box (Interval (-infinity_f, infinity_f), + Interval (0, 0))); + list::const_iterator end = src.buildings_.end (); + for (list::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 @@ -375,7 +440,7 @@ Skyline::Skyline (vector 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); } @@ -383,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 @@ -403,8 +469,22 @@ Skyline::insert (Box const &b, Real horizon_padding, Axis a) list other_bld; list my_bld; + if (isnan (b[other_axis (a)][LEFT]) + || isnan (b[other_axis (a)][RIGHT])) + { + programming_error ("insane box for skyline"); + return; + } + + /* do the same filtering as in Skyline (vector const&, etc.) */ + Interval iv = b[a]; + iv.widen (horizon_padding); + if (iv.length () <= EPS || b[other_axis (a)].is_empty ()) + 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_); } @@ -428,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::const_iterator i = buildings_.begin (); - list::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::const_iterator i = padded_this->buildings_.begin (); + list::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); @@ -485,7 +581,7 @@ Skyline::set_minimum_height (Real h) vector -Skyline::to_points (Axis a) const +Skyline::to_points (Axis horizon_axis) const { vector out; @@ -498,9 +594,9 @@ Skyline::to_points (Axis a) const start = i->end_; } - if (a == Y_AXIS) + if (horizon_axis == Y_AXIS) for (vsize i = 0; i < out.size (); i++) - out[i] = Offset (out[i][Y_AXIS], out[i][X_AXIS]); + out[i] = out[i].swapped (); return out; } @@ -508,69 +604,15 @@ Skyline::to_points (Axis a) const bool Skyline::is_empty () const { - return buildings_.empty (); -} - -Skyline_pair::Skyline_pair () - : skylines_ (Skyline (DOWN), Skyline (UP)) -{ -} - -Skyline_pair::Skyline_pair (vector const &boxes, Real padding, Axis a) - : skylines_ (Skyline (boxes, padding, a, DOWN), Skyline (boxes, padding, a, UP)) -{ -} - -Skyline_pair::Skyline_pair (Box const &b, Real padding, Axis a) - : skylines_ (Skyline (b, padding, a, DOWN), Skyline (b, padding, a, UP)) -{ + Building b = buildings_.front (); + return b.end_ == infinity_f && b.y_intercept_ == -infinity_f; } void -Skyline_pair::raise (Real r) -{ - skylines_[UP].raise (r); - skylines_[DOWN].raise (r); -} - -void -Skyline_pair::shift (Real r) -{ - skylines_[UP].shift (r); - skylines_[DOWN].shift (r); -} - -void -Skyline_pair::insert (Box const &b, Real padding, Axis a) -{ - skylines_[UP].insert (b, padding, a); - skylines_[DOWN].insert (b, padding, a); -} - -void -Skyline_pair::merge (Skyline_pair const &other) -{ - skylines_[UP].merge (other[UP]); - skylines_[DOWN].merge (other[DOWN]); -} - -bool -Skyline_pair::is_empty () const +Skyline::clear () { - return skylines_[UP].is_empty () - && skylines_[DOWN].is_empty (); -} - -Skyline& -Skyline_pair::operator [] (Direction d) -{ - return skylines_[d]; -} - -Skyline const& -Skyline_pair::operator [] (Direction d) const -{ - return skylines_[d]; + buildings_.clear (); + empty_skyline (&buildings_); } /****************************************************************/ @@ -580,10 +622,6 @@ IMPLEMENT_SIMPLE_SMOBS (Skyline); IMPLEMENT_TYPE_P (Skyline, "ly:skyline?"); IMPLEMENT_DEFAULT_EQUAL_P (Skyline); -IMPLEMENT_SIMPLE_SMOBS (Skyline_pair); -IMPLEMENT_TYPE_P (Skyline_pair, "ly:skyline-pair?"); -IMPLEMENT_DEFAULT_EQUAL_P (Skyline_pair); - SCM Skyline::mark_smob (SCM) { @@ -601,19 +639,3 @@ Skyline::print_smob (SCM s, SCM port, scm_print_state *) return 1; } - -SCM -Skyline_pair::mark_smob (SCM) -{ - return SCM_EOL; -} - -int -Skyline_pair::print_smob (SCM s, SCM port, scm_print_state *) -{ - Skyline_pair *r = (Skyline_pair *) SCM_CELL_WORD_1 (s); - (void) r; - - scm_puts ("#", port); - return 1; -}