2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 2006--2015 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 /* A skyline is a sequence of non-overlapping buildings: something like
35 Each building has a starting position, and ending position, a starting
36 height and an ending height.
38 The following invariants are observed:
39 - the start of the first building is at -infinity
40 - the end of the last building is at infinity
41 - if a building has infinite length (ie. the first and last buildings),
42 then its starting height and ending height are equal
43 - the end of one building is the same as the beginning of the next
46 We also allow skylines to point down (the structure is exactly the same,
47 but we think of the part above the line as being filled with mass and the
48 part below as being empty). ::distance finds the minimum distance between
49 an UP skyline and a DOWN skyline.
51 Note that we store DOWN skylines upside-down. That is, in order to compare
52 a DOWN skyline with an UP skyline, we need to flip the DOWN skyline first.
53 This means that the merging routine doesn't need to be aware of direction,
54 but the distance routine does.
56 From 2007 through 2012, buildings of width less than EPS were discarded,
57 citing numerical accuracy concerns. We remember that floating point
58 comparisons of nearly-equal values can be affected by rounding error.
59 Also, some target machines use the x87 floating point unit, which provides
60 extended precision for intermediate results held in registers. On this type
61 of hardware comparisons such as
62 double c = 1.0/3.0; boolean compare = (c == 1.0/3.0)
63 could go either way because the 1.0/3.0 is allowed to be kept
64 higher precision than the variable 'c'.
65 Alert to these considerations, we now accept buildings of zero-width.
68 ADD_SMOB_INIT (Skyline);
71 print_buildings (list<Building> const &b)
73 for (list<Building>::const_iterator i = b.begin (); i != b.end (); i++)
78 Skyline::print () const
80 print_buildings (buildings_);
84 Skyline::print_points () const
86 vector<Offset> ps (to_points (X_AXIS));
88 for (vsize i = 0; i < ps.size (); i++)
89 printf ("(%f,%f)%s", ps[i][X_AXIS], ps[i][Y_AXIS],
90 (i % 2) == 1 ? "\n" : " ");
93 Building::Building (Real start, Real start_height, Real end_height, Real end)
95 if (isinf (start) || isinf (end))
96 assert (start_height == end_height);
100 precompute (start, start_height, end_height, end);
103 Building::Building (Box const &b, Axis horizon_axis, Direction sky)
105 Real start = b[horizon_axis][LEFT];
106 Real end = b[horizon_axis][RIGHT];
107 Real height = sky * b[other_axis (horizon_axis)][sky];
111 precompute (start, height, height, end);
115 Building::precompute (Real start, Real start_height, Real end_height, Real end)
117 slope_ = 0.0; /* if they were both infinite, we would get nan, not 0, from the prev line */
118 if (start_height != end_height)
119 slope_ = (end_height - start_height) / (end - start);
121 assert (!isinf (slope_) && !isnan (slope_));
125 assert (start_height == end_height);
126 y_intercept_ = start_height;
128 else if (fabs (slope_) > 1e6)
129 // too steep to be stored in slope-intercept form, given round-off error
132 y_intercept_ = max (start_height, end_height);
135 y_intercept_ = start_height - slope_ * start;
139 Building::height (Real x) const
141 return isinf (x) ? y_intercept_ : slope_ * x + y_intercept_;
145 Building::print () const
147 printf ("%f x + %f from %f to %f\n", slope_, y_intercept_, start_, end_);
151 Building::intersection_x (Building const &other) const
153 Real ret = (y_intercept_ - other.y_intercept_) / (other.slope_ - slope_);
154 return isnan (ret) ? -infinity_f : ret;
157 // Returns a shift s such that (x + s, y) intersects the roof of
158 // this building. If no such shift exists, returns infinity_f.
160 Building::shift_to_intersect (Real x, Real y) const
162 // Solve for s: y = (x + s)*m + b
163 Real ret = (y - y_intercept_ - slope_ * x) / slope_;
165 if (ret >= start_ && ret <= end_ && !isinf (ret))
171 Building::above (Building const &other, Real x) const
173 return (isinf (y_intercept_) || isinf (other.y_intercept_) || isinf (x))
174 ? y_intercept_ > other.y_intercept_
175 : (slope_ - other.slope_) * x + y_intercept_ > other.y_intercept_;
178 // Remove redundant empty buildings from the skyline.
179 // If there are two adjacent empty buildings, they can be
182 Skyline::normalize ()
184 bool last_empty = false;
185 list<Building>::iterator i;
187 for (i = buildings_.begin (); i != buildings_.end (); i++)
189 if (last_empty && i->y_intercept_ == -infinity_f)
191 list<Building>::iterator last = i;
193 last->end_ = i->end_;
194 buildings_.erase (i);
197 last_empty = (i->y_intercept_ == -infinity_f);
200 assert (buildings_.front ().start_ == -infinity_f);
201 assert (buildings_.back ().end_ == infinity_f);
205 Skyline::internal_merge_skyline (list<Building> *sb, list<Building> *sc,
206 list<Building> *const result) const
208 if (sb->empty () || sc->empty ())
210 programming_error ("tried to merge an empty skyline");
214 Building b = sb->front ();
215 for (; !sc->empty (); sc->pop_front ())
217 /* Building b is continuing from the previous pass through the loop.
218 Building c is newly-considered, and starts no earlier than b started.
219 The comments draw b as if its roof had zero slope ----.
220 with dashes where b lies above c.
221 The roof of c could rise / or fall \ through the roof of b,
222 or the vertical sides | of c could intersect the roof of b. */
223 Building c = sc->front ();
224 if (b.end_ < c.end_) /* finish with b */
226 if (b.end_ <= b.start_) /* we are already finished with b */
228 else if (c.above (b, c.start_)) /* -| . | */
232 if (m.end_ > m.start_)
233 result->push_back (m);
234 if (b.above (c, b.end_)) /* -|\--. */
237 n.end_ = b.start_ = b.intersection_x (c);
238 result->push_back (n);
239 result->push_back (b);
244 if (c.above (b, b.end_)) /* ---/ . | */
245 b.end_ = b.intersection_x (c);
248 result->push_back (b);
250 /* 'c' continues further, so move it into 'b' for the next pass. */
254 else /* b.end_ > c.end_ so finish with c */
256 if (c.above (b, c.start_)) /* -| |---. */
260 if (m.end_ > m.start_)
261 result->push_back (m);
262 if (b.above (c, c.end_)) /* -| \---. */
263 c.end_ = b.intersection_x (c);
265 else if (c.above (b, c.end_)) /* ---/|--. */
268 c.start_ = m.end_ = b.intersection_x (c);
269 result->push_back (m);
271 else /* c is completely hidden by b */
273 result->push_back (c);
277 if (b.end_ > b.start_)
278 result->push_back (b);
282 empty_skyline (list<Building> *const ret)
284 ret->push_front (Building (-infinity_f, -infinity_f, -infinity_f, infinity_f));
288 Given Building 'b', build a skyline containing only that building.
291 single_skyline (Building b, list<Building> *const ret)
293 assert (b.end_ >= b.start_);
295 if (b.start_ != -infinity_f)
296 ret->push_back (Building (-infinity_f, -infinity_f,
297 -infinity_f, b.start_));
299 if (b.end_ != infinity_f)
300 ret->push_back (Building (b.end_, -infinity_f,
301 -infinity_f, infinity_f));
304 /* remove a non-overlapping set of boxes from BOXES and build a skyline
306 static list<Building>
307 non_overlapping_skyline (list<Building> *const buildings)
309 list<Building> result;
310 Real last_end = -infinity_f;
311 Building last_building (-infinity_f, -infinity_f, -infinity_f, infinity_f);
312 list<Building>::iterator i = buildings->begin ();
313 while (i != buildings->end ())
316 Real y1 = i->height (i->start_);
318 Real y2 = i->height (i->end_);
320 // Drop buildings that will obviously have no effect.
321 if (last_building.height (x1) >= y1
322 && last_building.end_ >= x2
323 && last_building.height (x2) >= y2)
325 list<Building>::iterator j = i++;
326 buildings->erase (j);
336 // Insert empty Buildings into any gaps. (TODO: is this needed? -KOH)
338 result.push_back (Building (last_end, -infinity_f, -infinity_f, x1));
340 result.push_back (*i);
344 list<Building>::iterator j = i++;
345 buildings->erase (j);
348 if (last_end < infinity_f)
349 result.push_back (Building (last_end, -infinity_f, -infinity_f, infinity_f));
353 class LessThanBuilding
356 bool operator () (Building const &b1, Building const &b2)
358 return b1.start_ < b2.start_
359 || (b1.start_ == b2.start_ && b1.height (b1.start_) > b2.height (b1.start_));
364 BUILDINGS is a list of buildings, but they could be overlapping
365 and in any order. The returned list of buildings is ordered and non-overlapping.
368 Skyline::internal_build_skyline (list<Building> *buildings) const
370 vsize size = buildings->size ();
374 list<Building> result;
375 empty_skyline (&result);
380 list<Building> result;
381 single_skyline (buildings->front (), &result);
385 deque<list<Building> > partials;
386 buildings->sort (LessThanBuilding ());
387 while (!buildings->empty ())
388 partials.push_back (non_overlapping_skyline (buildings));
390 /* we'd like to say while (partials->size () > 1) but that's O (n).
391 Instead, we exit in the middle of the loop */
392 while (!partials.empty ())
394 list<Building> merged;
395 list<Building> one = partials.front ();
396 partials.pop_front ();
397 if (partials.empty ())
400 list<Building> two = partials.front ();
401 partials.pop_front ();
402 internal_merge_skyline (&one, &two, &merged);
403 partials.push_back (merged);
406 return list<Building> ();
412 empty_skyline (&buildings_);
415 Skyline::Skyline (Direction sky)
418 empty_skyline (&buildings_);
422 Build skyline from a set of boxes.
424 Boxes should be non-empty on both axes. Otherwise, they will be ignored
426 Skyline::Skyline (vector<Box> const &boxes, Axis horizon_axis, Direction sky)
428 list<Building> buildings;
431 for (vsize i = 0; i < boxes.size (); i++)
432 if (!boxes[i].is_empty (X_AXIS)
433 && !boxes[i].is_empty (Y_AXIS))
434 buildings.push_front (Building (boxes[i], horizon_axis, sky));
436 buildings_ = internal_build_skyline (&buildings);
441 build skyline from a set of line segments.
443 Segments can be articulated from left to right or right to left.
444 In the case of the latter, they will be stored internally as left to right.
446 Skyline::Skyline (vector<Drul_array<Offset> > const &segments, Axis horizon_axis, Direction sky)
448 list<Building> buildings;
451 for (vsize i = 0; i < segments.size (); i++)
453 Drul_array<Offset> const &seg = segments[i];
454 Offset left = seg[LEFT];
455 Offset right = seg[RIGHT];
456 if (left[horizon_axis] > right[horizon_axis])
459 Real x1 = left[horizon_axis];
460 Real x2 = right[horizon_axis];
461 Real y1 = left[other_axis (horizon_axis)] * sky;
462 Real y2 = right[other_axis (horizon_axis)] * sky;
465 buildings.push_back (Building (x1, y1, y2, x2));
468 buildings_ = internal_build_skyline (&buildings);
472 Skyline::Skyline (vector<Skyline_pair> const &skypairs, Direction sky)
476 deque<Skyline> partials;
477 for (vsize i = 0; i < skypairs.size (); i++)
478 partials.push_back (Skyline ((skypairs[i])[sky]));
480 while (partials.size () > 1)
482 Skyline one = partials.front ();
483 partials.pop_front ();
484 Skyline two = partials.front ();
485 partials.pop_front ();
488 partials.push_back (one);
491 if (partials.size ())
492 buildings_.swap (partials.front ().buildings_);
497 Skyline::Skyline (Box const &b, Axis horizon_axis, Direction sky)
500 if (!b.is_empty (X_AXIS) && !b.is_empty (Y_AXIS))
502 Building front (b, horizon_axis, sky);
503 single_skyline (front, &buildings_);
509 Skyline::merge (Skyline const &other)
511 assert (sky_ == other.sky_);
513 if (other.is_empty ())
518 buildings_ = other.buildings_;
522 list<Building> other_bld (other.buildings_);
523 list<Building> my_bld;
524 my_bld.splice (my_bld.begin (), buildings_);
525 internal_merge_skyline (&other_bld, &my_bld, &buildings_);
530 Skyline::insert (Box const &b, Axis a)
532 list<Building> other_bld;
533 list<Building> my_bld;
535 if (isnan (b[other_axis (a)][LEFT])
536 || isnan (b[other_axis (a)][RIGHT]))
538 programming_error ("insane box for skyline");
542 /* do the same filtering as in Skyline (vector<Box> const&, etc.) */
543 if (b.is_empty (X_AXIS) || b.is_empty (Y_AXIS))
546 my_bld.splice (my_bld.begin (), buildings_);
547 single_skyline (Building (b, a, sky_), &other_bld);
548 internal_merge_skyline (&other_bld, &my_bld, &buildings_);
553 Skyline::raise (Real r)
555 list<Building>::iterator end = buildings_.end ();
556 for (list<Building>::iterator i = buildings_.begin (); i != end; i++)
557 i->y_intercept_ += sky_ * r;
561 Skyline::shift (Real s)
563 list<Building>::iterator end = buildings_.end ();
564 for (list<Building>::iterator i = buildings_.begin (); i != end; i++)
568 i->y_intercept_ -= s * i->slope_;
573 Skyline::distance (Skyline const &other, Real horizon_padding) const
576 return internal_distance (other, horizon_padding, &dummy);
580 Skyline::touching_point (Skyline const &other, Real horizon_padding) const
583 internal_distance (other, horizon_padding, &touch);
588 Skyline::internal_distance (Skyline const &other, Real horizon_padding, Real *touch_point) const
590 if (horizon_padding == 0.0)
591 return internal_distance (other, touch_point);
593 // Note that it is not necessary to build a padded version of other,
594 // because the same effect can be achieved just by doubling horizon_padding.
595 Skyline padded_this = padded (horizon_padding);
596 return padded_this.internal_distance (other, touch_point);
600 Skyline::padded (Real horizon_padding) const
602 if (horizon_padding < 0.0)
603 warning ("Cannot have negative horizon padding. Junking.");
605 if (horizon_padding <= 0.0)
608 list<Building> pad_buildings;
609 for (list<Building>::const_iterator i = buildings_.begin (); i != buildings_.end (); ++i)
611 if (i->start_ > -infinity_f)
613 Real height = i->height (i->start_);
614 if (height > -infinity_f)
616 // Add the sloped building that pads the left side of the current building.
617 Real start = i->start_ - 2 * horizon_padding;
618 Real end = i->start_ - horizon_padding;
619 pad_buildings.push_back (Building (start, height - horizon_padding, height, end));
621 // Add the flat building that pads the left side of the current building.
622 start = i->start_ - horizon_padding;
624 pad_buildings.push_back (Building (start, height, height, end));
628 if (i->end_ < infinity_f)
630 Real height = i->height (i->end_);
631 if (height > -infinity_f)
633 // Add the flat building that pads the right side of the current building.
634 Real start = i->end_;
635 Real end = start + horizon_padding;
636 pad_buildings.push_back (Building (start, height, height, end));
638 // Add the sloped building that pads the right side of the current building.
640 end += horizon_padding;
641 pad_buildings.push_back (Building (start, height, height - horizon_padding, end));
646 // The buildings may be overlapping, so resolve that.
647 list<Building> pad_skyline = internal_build_skyline (&pad_buildings);
649 // Merge the padding with the original, to make a new skyline.
650 Skyline padded (sky_);
651 list<Building> my_buildings = buildings_;
652 padded.buildings_.clear ();
653 internal_merge_skyline (&pad_skyline, &my_buildings, &padded.buildings_);
660 Skyline::internal_distance (Skyline const &other, Real *touch_point) const
662 assert (sky_ == -other.sky_);
664 list<Building>::const_iterator i = buildings_.begin ();
665 list<Building>::const_iterator j = other.buildings_.begin ();
667 Real dist = -infinity_f;
668 Real start = -infinity_f;
669 Real touch = -infinity_f;
670 while (i != buildings_.end () && j != other.buildings_.end ())
672 Real end = min (i->end_, j->end_);
673 Real start_dist = i->height (start) + j->height (start);
674 Real end_dist = i->height (end) + j->height (end);
675 dist = max (dist, max (start_dist, end_dist));
677 if (end_dist == dist)
679 else if (start_dist == dist)
682 if (i->end_ <= j->end_)
689 *touch_point = touch;
694 Skyline::height (Real airplane) const
696 assert (!isinf (airplane));
698 list<Building>::const_iterator i;
699 for (i = buildings_.begin (); i != buildings_.end (); i++)
701 if (i->end_ >= airplane)
702 return sky_ * i->height (airplane);
710 Skyline::max_height () const
712 Real ret = -infinity_f;
714 list<Building>::const_iterator i;
715 for (i = buildings_.begin (); i != buildings_.end (); ++i)
717 ret = max (ret, i->height (i->start_));
718 ret = max (ret, i->height (i->end_));
725 Skyline::direction () const
731 Skyline::left () const
733 for (list<Building>::const_iterator i (buildings_.begin ());
734 i != buildings_.end (); i++)
735 if (i->y_intercept_ > -infinity_f)
742 Skyline::right () const
744 for (list<Building>::const_reverse_iterator i (buildings_.rbegin ());
745 i != buildings_.rend (); ++i)
746 if (i->y_intercept_ > -infinity_f)
753 Skyline::max_height_position () const
756 s.set_minimum_height (0);
757 return touching_point (s);
761 Skyline::set_minimum_height (Real h)
764 s.buildings_.front ().y_intercept_ = h * sky_;
769 Skyline::to_points (Axis horizon_axis) const
773 Real start = -infinity_f;
774 for (list<Building>::const_iterator i (buildings_.begin ());
775 i != buildings_.end (); i++)
777 out.push_back (Offset (start, sky_ * i->height (start)));
778 out.push_back (Offset (i->end_, sky_ * i->height (i->end_)));
782 if (horizon_axis == Y_AXIS)
783 for (vsize i = 0; i < out.size (); i++)
784 out[i] = out[i].swapped ();
790 Skyline::is_empty () const
792 if (!buildings_.size ())
794 Building b = buildings_.front ();
795 return b.end_ == infinity_f && b.y_intercept_ == -infinity_f;
802 empty_skyline (&buildings_);
805 /****************************************************************/
807 const char Skyline::type_p_name_[] = "ly:skyline?";
809 MAKE_SCHEME_CALLBACK_WITH_OPTARGS (Skyline, get_touching_point, 3, 1, "")
811 Skyline::get_touching_point (SCM skyline_scm, SCM other_skyline_scm, SCM horizon_padding_scm)
813 LY_ASSERT_SMOB (Skyline, other_skyline_scm, 1);
815 Real horizon_padding = 0;
816 if (!SCM_UNBNDP (horizon_padding_scm))
818 LY_ASSERT_TYPE (scm_is_number, horizon_padding_scm, 3);
819 horizon_padding = scm_to_double (horizon_padding_scm);
822 Skyline *skyline = Skyline::unsmob (skyline_scm);
823 Skyline *other_skyline = Skyline::unsmob (other_skyline_scm);
824 return scm_from_double (skyline->touching_point (*other_skyline, horizon_padding));
827 MAKE_SCHEME_CALLBACK_WITH_OPTARGS (Skyline, get_distance, 3, 1, "")
829 Skyline::get_distance (SCM skyline_scm, SCM other_skyline_scm, SCM horizon_padding_scm)
831 LY_ASSERT_SMOB (Skyline, other_skyline_scm, 1);
833 Real horizon_padding = 0;
834 if (!SCM_UNBNDP (horizon_padding_scm))
836 LY_ASSERT_TYPE (scm_is_number, horizon_padding_scm, 3);
837 horizon_padding = scm_to_double (horizon_padding_scm);
840 Skyline *skyline = Skyline::unsmob (skyline_scm);
841 Skyline *other_skyline = Skyline::unsmob (other_skyline_scm);
842 return scm_from_double (skyline->distance (*other_skyline, horizon_padding));
845 MAKE_SCHEME_CALLBACK (Skyline, get_max_height, 1)
847 Skyline::get_max_height (SCM skyline_scm)
849 return scm_from_double (Skyline::unsmob (skyline_scm)->max_height ());
852 MAKE_SCHEME_CALLBACK (Skyline, get_max_height_position, 1)
854 Skyline::get_max_height_position (SCM skyline_scm)
856 return scm_from_double (Skyline::unsmob (skyline_scm)->max_height_position ());
859 MAKE_SCHEME_CALLBACK (Skyline, get_height, 2)
861 Skyline::get_height (SCM skyline_scm, SCM x_scm)
863 Real x = robust_scm2double (x_scm, 0.0);
864 return scm_from_double (Skyline::unsmob (skyline_scm)->height (x));
867 LY_DEFINE (ly_skyline_empty_p, "ly:skyline-empty?",
869 "Return whether @var{sky} is empty.")
871 Skyline *s = Skyline::unsmob (sky);
872 LY_ASSERT_SMOB (Skyline, sky, 1);
873 return scm_from_bool (s->is_empty ());