2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 2006--2012 Joe Neeman <joeneeman@gmail.com>
6 LilyPond is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 LilyPond is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
21 #include "skyline-pair.hh"
25 #include "ly-smobs.icc"
27 /* A skyline is a sequence of non-overlapping buildings: something like
37 Each building has a starting position, and ending position, a starting
38 height and an ending height.
40 The following invariants are observed:
41 - the start of the first building is at -infinity
42 - the end of the last building is at infinity
43 - if a building has infinite length (ie. the first and last buildings),
44 then its starting height and ending height are equal
45 - the end of one building is the same as the beginning of the next
48 We also allow skylines to point down (the structure is exactly the same,
49 but we think of the part above the line as being filled with mass and the
50 part below as being empty). ::distance finds the minimum distance between
51 an UP skyline and a DOWN skyline.
53 Note that we store DOWN skylines upside-down. That is, in order to compare
54 a DOWN skyline with an UP skyline, we need to flip the DOWN skyline first.
55 This means that the merging routine doesn't need to be aware of direction,
56 but the distance routine does.
60 print_buildings (list<Building> const &b)
62 for (list<Building>::const_iterator i = b.begin (); i != b.end (); i++)
67 Skyline::print () const
69 print_buildings (buildings_);
73 Skyline::print_points () const
75 vector<Offset> ps (to_points (X_AXIS));
77 for (vsize i = 0; i < ps.size (); i++)
78 printf ("(%f,%f)%s", ps[i][X_AXIS], ps[i][Y_AXIS],
79 (i % 2) == 1 ? "\n" : " ");
82 Building::Building (Real start, Real start_height, Real end_height, Real end)
84 if (isinf (start) || isinf (end))
85 assert (start_height == end_height);
89 precompute (start, start_height, end_height, end);
92 Building::Building (Box const &b, Axis horizon_axis, Direction sky)
94 Real start = b[horizon_axis][LEFT];
95 Real end = b[horizon_axis][RIGHT];
96 Real height = sky * b[other_axis (horizon_axis)][sky];
100 precompute (start, height, height, end);
104 Building::precompute (Real start, Real start_height, Real end_height, Real end)
106 slope_ = 0.0; /* if they were both infinite, we would get nan, not 0, from the prev line */
107 if (start_height != end_height)
108 slope_ = (end_height - start_height) / (end - start);
110 assert (!isinf (slope_) && !isnan (slope_));
114 assert (start_height == end_height);
115 y_intercept_ = start_height;
118 y_intercept_ = start_height - slope_ * start;
122 Building::height (Real x) const
124 return isinf (x) ? y_intercept_ : slope_ * x + y_intercept_;
128 Building::print () const
130 printf ("%f x + %f from %f to %f\n", slope_, y_intercept_, start_, end_);
134 Building::intersection_x (Building const &other) const
136 Real ret = (y_intercept_ - other.y_intercept_) / (other.slope_ - slope_);
137 return isnan (ret) ? -infinity_f : ret;
141 Building::leading_part (Real chop)
143 assert (chop <= end_);
147 // Returns a shift s such that (x + s, y) intersects the roof of
148 // this building. If no such shift exists, returns infinity_f.
150 Building::shift_to_intersect (Real x, Real y) const
152 // Solve for s: y = (x + s)*m + b
153 Real ret = (y - y_intercept_ - slope_ * x) / slope_;
155 if (ret >= start_ && ret <= end_ && !isinf (ret))
161 first_intersection (Building const &b, list<Building> *const s, Real start_x)
163 while (!s->empty () && start_x < b.end_)
165 Building c = s->front ();
167 // conceals and intersection_x involve multiplication and
168 // division. Avoid that, if we can.
169 if (c.y_intercept_ == -infinity_f)
178 if (c.conceals (b, start_x))
181 Real i = b.intersection_x (c);
182 if (i > start_x && i <= b.end_ && i <= c.end_)
193 Building::conceals (Building const &other, Real x) const
195 if (slope_ == other.slope_)
196 return y_intercept_ > other.y_intercept_;
198 /* their slopes were not equal, so there is an intersection point */
199 Real i = intersection_x (other);
200 return (i <= x && slope_ > other.slope_)
201 || (i > x && slope_ < other.slope_);
204 // Remove redundant empty buildings from the skyline.
205 // If there are two adjacent empty buildings, they can be
208 Skyline::normalize ()
210 bool last_empty = false;
211 list<Building>::iterator i;
213 for (i = buildings_.begin (); i != buildings_.end (); i++)
215 if (last_empty && i->y_intercept_ == -infinity_f)
217 list<Building>::iterator last = i;
219 last->end_ = i->end_;
220 buildings_.erase (i);
223 last_empty = (i->y_intercept_ == -infinity_f);
226 assert (buildings_.front ().start_ == -infinity_f);
227 assert (buildings_.back ().end_ == infinity_f);
233 // Since a skyline should always be normalized, we can
234 // assume that there are never two adjacent empty buildings.
235 // That is, if center is empty then left and right are not.
236 list<Building>::iterator left = buildings_.begin ();
237 list<Building>::iterator center = buildings_.begin ();
238 list<Building>::iterator right;
240 for (right = buildings_.begin (); right != buildings_.end (); right++)
242 if (center != buildings_.begin () && center->y_intercept_ == -infinity_f)
244 Real p1 = left->height (left->end_);
245 Real p2 = right->height (right->start_);
246 *center = Building (center->start_, p1, p2, center->end_);
255 Skyline::internal_merge_skyline (list<Building> *s1, list<Building> *s2,
256 list<Building> *const result) const
258 if (s1->empty () || s2->empty ())
260 programming_error ("tried to merge an empty skyline");
264 Real x = -infinity_f;
265 Real last_end = -infinity_f;
266 while (!s1->empty ())
268 if (s2->front ().conceals (s1->front (), x))
271 Building b = s1->front ();
272 Building c = s2->front ();
274 // Optimization: if the other skyline is empty at this point,
275 // we can avoid testing some intersections. Just grab as many
276 // buildings from s1 as we can, and shove them onto the output.
277 if (c.y_intercept_ == -infinity_f
280 list<Building>::iterator i = s1->begin ();
282 while (i != s1->end () && i->end_ <= c.end_)
285 s1->front ().start_ = x;
286 result->splice (result->end (), *s1, s1->begin (), i);
287 x = result->back ().end_;
292 Real end = first_intersection (b, s2, x);
296 result->push_back (b);
302 b.leading_part (end);
305 result->push_back (b);
308 if (end >= s1->front ().end_)
316 empty_skyline (list<Building> *const ret)
318 ret->push_front (Building (-infinity_f, -infinity_f, -infinity_f, infinity_f));
322 Given Building 'b', build a skyline containing only that building.
325 single_skyline (Building b, list<Building> *const ret)
327 assert (b.end_ >= b.start_);
329 if (b.start_ != -infinity_f)
330 ret->push_back (Building (-infinity_f, -infinity_f,
331 -infinity_f, b.start_));
333 if (b.end_ != infinity_f)
334 ret->push_back (Building (b.end_, -infinity_f,
335 -infinity_f, infinity_f));
338 /* remove a non-overlapping set of boxes from BOXES and build a skyline
340 static list<Building>
341 non_overlapping_skyline (list<Building> *const buildings)
343 list<Building> result;
344 Real last_end = -infinity_f;
345 Building last_building (-infinity_f, -infinity_f, -infinity_f, infinity_f);
346 list<Building>::iterator i = buildings->begin ();
347 while (i != buildings->end ())
350 Real y1 = i->height (i->start_);
352 Real y2 = i->height (i->end_);
354 // Drop buildings that will obviously have no effect.
355 if (last_building.height (x1) >= y1
356 && last_building.end_ >= x2
357 && last_building.height (x2) >= y2)
359 list<Building>::iterator j = i++;
360 buildings->erase (j);
371 result.push_back (Building (last_end, -infinity_f, -infinity_f, x1));
373 result.push_back (*i);
377 list<Building>::iterator j = i++;
378 buildings->erase (j);
381 if (last_end < infinity_f)
382 result.push_back (Building (last_end, -infinity_f, -infinity_f, infinity_f));
386 class LessThanBuilding
389 bool operator () (Building const &b1, Building const &b2)
391 return b1.start_ < b2.start_
392 || (b1.start_ == b2.start_ && b1.height (b1.start_) > b2.height (b1.start_));
397 BUILDINGS is a list of buildings, but they could be overlapping
398 and in any order. The returned list of buildings is ordered and non-overlapping.
401 Skyline::internal_build_skyline (list<Building> *buildings) const
403 vsize size = buildings->size ();
407 list<Building> result;
408 empty_skyline (&result);
413 list<Building> result;
414 single_skyline (buildings->front (), &result);
418 deque<list<Building> > partials;
419 buildings->sort (LessThanBuilding ());
420 while (!buildings->empty ())
421 partials.push_back (non_overlapping_skyline (buildings));
423 /* we'd like to say while (partials->size () > 1) but that's O (n).
424 Instead, we exit in the middle of the loop */
425 while (!partials.empty ())
427 list<Building> merged;
428 list<Building> one = partials.front ();
429 partials.pop_front ();
430 if (partials.empty ())
433 list<Building> two = partials.front ();
434 partials.pop_front ();
435 internal_merge_skyline (&one, &two, &merged);
436 partials.push_back (merged);
439 return list<Building> ();
445 empty_skyline (&buildings_);
448 Skyline::Skyline (Skyline const &src)
452 /* doesn't a list's copy constructor do this? -- jneem */
453 for (list<Building>::const_iterator i = src.buildings_.begin ();
454 i != src.buildings_.end (); i++)
456 buildings_.push_back (Building ((*i)));
460 Skyline::Skyline (Direction sky)
463 empty_skyline (&buildings_);
467 Build skyline from a set of boxes.
469 Boxes should be non-empty on both axes. Otherwise, they will be ignored
471 Skyline::Skyline (vector<Box> const &boxes, Axis horizon_axis, Direction sky)
473 list<Building> buildings;
476 for (vsize i = 0; i < boxes.size (); i++)
477 if (!boxes[i].is_empty ())
478 buildings.push_front (Building (boxes[i], horizon_axis, sky));
480 buildings_ = internal_build_skyline (&buildings);
485 build skyline from a set of line segments.
487 Segments can be articulated from left to right or right to left.
488 In the case of the latter, they will be stored internally as left to right.
490 Skyline::Skyline (vector<Drul_array<Offset> > const &segments, Axis horizon_axis, Direction sky)
492 list<Building> buildings;
495 for (vsize i = 0; i < segments.size (); i++)
497 Drul_array<Offset> const &seg = segments[i];
498 Offset left = seg[LEFT];
499 Offset right = seg[RIGHT];
500 if (left[horizon_axis] > right[horizon_axis])
503 Real x1 = left[horizon_axis];
504 Real x2 = right[horizon_axis];
505 Real y1 = left[other_axis (horizon_axis)] * sky;
506 Real y2 = right[other_axis (horizon_axis)] * sky;
509 buildings.push_back (Building (x1, y1, y2, x2));
512 buildings_ = internal_build_skyline (&buildings);
516 Skyline::Skyline (vector<Skyline_pair> const &skypairs, Direction sky)
520 deque<Skyline> partials;
521 for (vsize i = 0; i < skypairs.size (); i++)
522 partials.push_back (Skyline ((skypairs[i])[sky]));
524 while (partials.size () > 1)
526 Skyline one = partials.front ();
527 partials.pop_front ();
528 Skyline two = partials.front ();
529 partials.pop_front ();
532 partials.push_back (one);
535 if (partials.size ())
536 buildings_.swap (partials.front ().buildings_);
541 Skyline::Skyline (Box const &b, Axis horizon_axis, Direction sky)
544 Building front (b, horizon_axis, sky);
545 single_skyline (front, &buildings_);
550 Skyline::merge (Skyline const &other)
552 assert (sky_ == other.sky_);
554 if (other.is_empty ())
559 buildings_ = other.buildings_;
563 list<Building> other_bld (other.buildings_);
564 list<Building> my_bld;
565 my_bld.splice (my_bld.begin (), buildings_);
566 internal_merge_skyline (&other_bld, &my_bld, &buildings_);
571 Skyline::insert (Box const &b, Axis a)
573 list<Building> other_bld;
574 list<Building> my_bld;
576 if (isnan (b[other_axis (a)][LEFT])
577 || isnan (b[other_axis (a)][RIGHT]))
579 programming_error ("insane box for skyline");
583 /* do the same filtering as in Skyline (vector<Box> const&, etc.) */
587 my_bld.splice (my_bld.begin (), buildings_);
588 single_skyline (Building (b, a, sky_), &other_bld);
589 internal_merge_skyline (&other_bld, &my_bld, &buildings_);
594 Skyline::raise (Real r)
596 list<Building>::iterator end = buildings_.end ();
597 for (list<Building>::iterator i = buildings_.begin (); i != end; i++)
598 i->y_intercept_ += sky_ * r;
602 Skyline::shift (Real s)
604 list<Building>::iterator end = buildings_.end ();
605 for (list<Building>::iterator i = buildings_.begin (); i != end; i++)
609 i->y_intercept_ -= s * i->slope_;
614 Skyline::distance (Skyline const &other, Real horizon_padding) const
617 return internal_distance (other, horizon_padding, &dummy);
621 Skyline::touching_point (Skyline const &other, Real horizon_padding) const
624 internal_distance (other, horizon_padding, &touch);
629 Skyline::internal_distance (Skyline const &other, Real horizon_padding, Real *touch_point) const
631 if (horizon_padding == 0.0)
632 return internal_distance (other, touch_point);
634 // Note that it is not necessary to build a padded version of other,
635 // because the same effect can be achieved just by doubling horizon_padding.
636 Skyline padded_this = padded (horizon_padding);
637 return padded_this.internal_distance (other, touch_point);
641 Skyline::padded (Real horizon_padding) const
643 if (horizon_padding < 0.0)
644 warning ("Cannot have negative horizon padding. Junking.");
646 if (horizon_padding <= 0.0)
649 list<Building> pad_buildings;
650 for (list<Building>::const_iterator i = buildings_.begin (); i != buildings_.end (); ++i)
652 if (i->start_ > -infinity_f)
654 Real height = i->height (i->start_);
655 if (height > -infinity_f)
657 // Add the sloped building that pads the left side of the current building.
658 Real start = i->start_ - 2 * horizon_padding;
659 Real end = i->start_ - horizon_padding;
660 pad_buildings.push_back (Building (start, height - horizon_padding, height, end));
662 // Add the flat building that pads the left side of the current building.
663 start = i->start_ - horizon_padding;
665 pad_buildings.push_back (Building (start, height, height, end));
669 if (i->end_ < infinity_f)
671 Real height = i->height (i->end_);
672 if (height > -infinity_f)
674 // Add the flat building that pads the right side of the current building.
675 Real start = i->end_;
676 Real end = start + horizon_padding;
677 pad_buildings.push_back (Building (start, height, height, end));
679 // Add the sloped building that pads the right side of the current building.
681 end += horizon_padding;
682 pad_buildings.push_back (Building (start, height, height - horizon_padding, end));
687 // The buildings may be overlapping, so resolve that.
688 list<Building> pad_skyline = internal_build_skyline (&pad_buildings);
690 // Merge the padding with the original, to make a new skyline.
691 Skyline padded (sky_);
692 list<Building> my_buildings = buildings_;
693 padded.buildings_.clear ();
694 internal_merge_skyline (&pad_skyline, &my_buildings, &padded.buildings_);
701 Skyline::internal_distance (Skyline const &other, Real *touch_point) const
703 assert (sky_ == -other.sky_);
705 list<Building>::const_iterator i = buildings_.begin ();
706 list<Building>::const_iterator j = other.buildings_.begin ();
708 Real dist = -infinity_f;
709 Real start = -infinity_f;
710 Real touch = -infinity_f;
711 while (i != buildings_.end () && j != other.buildings_.end ())
713 Real end = min (i->end_, j->end_);
714 Real start_dist = i->height (start) + j->height (start);
715 Real end_dist = i->height (end) + j->height (end);
716 dist = max (dist, max (start_dist, end_dist));
718 if (end_dist == dist)
720 else if (start_dist == dist)
723 if (i->end_ <= j->end_)
730 *touch_point = touch;
735 Skyline::height (Real airplane) const
737 assert (!isinf (airplane));
739 list<Building>::const_iterator i;
740 for (i = buildings_.begin (); i != buildings_.end (); i++)
742 if (i->end_ >= airplane)
743 return sky_ * i->height (airplane);
751 Skyline::max_height () const
753 Real ret = -infinity_f;
755 list<Building>::const_iterator i;
756 for (i = buildings_.begin (); i != buildings_.end (); ++i)
758 ret = max (ret, i->height (i->start_));
759 ret = max (ret, i->height (i->end_));
766 Skyline::direction () const
772 Skyline::left () const
774 for (list<Building>::const_iterator i (buildings_.begin ());
775 i != buildings_.end (); i++)
776 if (i->y_intercept_ > -infinity_f)
783 Skyline::right () const
785 for (list<Building>::const_reverse_iterator i (buildings_.rbegin ());
786 i != buildings_.rend (); ++i)
787 if (i->y_intercept_ > -infinity_f)
794 Skyline::max_height_position () const
797 s.set_minimum_height (0);
798 return touching_point (s);
802 Skyline::set_minimum_height (Real h)
805 s.buildings_.front ().y_intercept_ = h * sky_;
810 Skyline::to_points (Axis horizon_axis) const
814 Real start = -infinity_f;
815 for (list<Building>::const_iterator i (buildings_.begin ());
816 i != buildings_.end (); i++)
818 out.push_back (Offset (start, sky_ * i->height (start)));
819 out.push_back (Offset (i->end_, sky_ * i->height (i->end_)));
823 if (horizon_axis == Y_AXIS)
824 for (vsize i = 0; i < out.size (); i++)
825 out[i] = out[i].swapped ();
831 Skyline::is_empty () const
833 if (!buildings_.size ())
835 Building b = buildings_.front ();
836 return b.end_ == infinity_f && b.y_intercept_ == -infinity_f;
843 empty_skyline (&buildings_);
846 /****************************************************************/
848 IMPLEMENT_SIMPLE_SMOBS (Skyline);
849 IMPLEMENT_TYPE_P (Skyline, "ly:skyline?");
850 IMPLEMENT_DEFAULT_EQUAL_P (Skyline);
853 Skyline::mark_smob (SCM s)
855 ASSERT_LIVE_IS_ALLOWED (s);
860 Skyline::print_smob (SCM s, SCM port, scm_print_state *)
862 Skyline *r = (Skyline *) SCM_CELL_WORD_1 (s);
865 scm_puts ("#<Skyline>", port);
870 MAKE_SCHEME_CALLBACK_WITH_OPTARGS (Skyline, get_touching_point, 3, 1, "")
872 Skyline::get_touching_point (SCM skyline_scm, SCM other_skyline_scm, SCM horizon_padding_scm)
874 LY_ASSERT_SMOB (Skyline, other_skyline_scm, 1);
876 Real horizon_padding = 0;
877 if (horizon_padding_scm != SCM_UNDEFINED)
879 LY_ASSERT_TYPE (scm_is_number, horizon_padding_scm, 3);
880 horizon_padding = scm_to_double (horizon_padding_scm);
883 Skyline *skyline = Skyline::unsmob (skyline_scm);
884 Skyline *other_skyline = Skyline::unsmob (other_skyline_scm);
885 return scm_from_double (skyline->touching_point (*other_skyline, horizon_padding));
888 MAKE_SCHEME_CALLBACK_WITH_OPTARGS (Skyline, get_distance, 3, 1, "")
890 Skyline::get_distance (SCM skyline_scm, SCM other_skyline_scm, SCM horizon_padding_scm)
892 LY_ASSERT_SMOB (Skyline, other_skyline_scm, 1);
894 Real horizon_padding = 0;
895 if (horizon_padding_scm != SCM_UNDEFINED)
897 LY_ASSERT_TYPE (scm_is_number, horizon_padding_scm, 3);
898 horizon_padding = scm_to_double (horizon_padding_scm);
901 Skyline *skyline = Skyline::unsmob (skyline_scm);
902 Skyline *other_skyline = Skyline::unsmob (other_skyline_scm);
903 return scm_from_double (skyline->distance (*other_skyline, horizon_padding));
906 MAKE_SCHEME_CALLBACK (Skyline, get_max_height, 1)
908 Skyline::get_max_height (SCM skyline_scm)
910 return scm_from_double (Skyline::unsmob (skyline_scm)->max_height ());
913 MAKE_SCHEME_CALLBACK (Skyline, get_max_height_position, 1)
915 Skyline::get_max_height_position (SCM skyline_scm)
917 return scm_from_double (Skyline::unsmob (skyline_scm)->max_height_position ());
920 MAKE_SCHEME_CALLBACK (Skyline, get_height, 2)
922 Skyline::get_height (SCM skyline_scm, SCM x_scm)
924 Real x = robust_scm2double (x_scm, 0.0);
925 return scm_from_double (Skyline::unsmob (skyline_scm)->height (x));
928 LY_DEFINE (ly_skyline_empty_p, "ly:skyline-empty?",
930 "Return whether @var{sky} is empty.")
932 Skyline *s = Skyline::unsmob (sky);
933 LY_ASSERT_SMOB (Skyline, sky, 1);
934 return scm_from_bool (s->is_empty ());