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.
69 print_buildings (list<Building> const &b)
71 for (list<Building>::const_iterator i = b.begin (); i != b.end (); i++)
76 Skyline::print () const
78 print_buildings (buildings_);
82 Skyline::print_points () const
84 vector<Offset> ps (to_points (X_AXIS));
86 for (vsize i = 0; i < ps.size (); i++)
87 printf ("(%f,%f)%s", ps[i][X_AXIS], ps[i][Y_AXIS],
88 (i % 2) == 1 ? "\n" : " ");
91 Building::Building (Real start, Real start_height, Real end_height, Real end)
93 if (isinf (start) || isinf (end))
94 assert (start_height == end_height);
98 precompute (start, start_height, end_height, end);
101 Building::Building (Box const &b, Axis horizon_axis, Direction sky)
103 Real start = b[horizon_axis][LEFT];
104 Real end = b[horizon_axis][RIGHT];
105 Real height = sky * b[other_axis (horizon_axis)][sky];
109 precompute (start, height, height, end);
113 Building::precompute (Real start, Real start_height, Real end_height, Real end)
115 slope_ = 0.0; /* if they were both infinite, we would get nan, not 0, from the prev line */
116 if (start_height != end_height)
117 slope_ = (end_height - start_height) / (end - start);
119 assert (!isinf (slope_) && !isnan (slope_));
123 assert (start_height == end_height);
124 y_intercept_ = start_height;
126 else if (fabs (slope_) > 1e6)
127 // too steep to be stored in slope-intercept form, given round-off error
130 y_intercept_ = max (start_height, end_height);
133 y_intercept_ = start_height - slope_ * start;
137 Building::height (Real x) const
139 return isinf (x) ? y_intercept_ : slope_ * x + y_intercept_;
143 Building::print () const
145 printf ("%f x + %f from %f to %f\n", slope_, y_intercept_, start_, end_);
149 Building::intersection_x (Building const &other) const
151 Real ret = (y_intercept_ - other.y_intercept_) / (other.slope_ - slope_);
152 return isnan (ret) ? -infinity_f : ret;
155 // Returns a shift s such that (x + s, y) intersects the roof of
156 // this building. If no such shift exists, returns infinity_f.
158 Building::shift_to_intersect (Real x, Real y) const
160 // Solve for s: y = (x + s)*m + b
161 Real ret = (y - y_intercept_ - slope_ * x) / slope_;
163 if (ret >= start_ && ret <= end_ && !isinf (ret))
169 Building::above (Building const &other, Real x) const
171 return (isinf (y_intercept_) || isinf (other.y_intercept_) || isinf (x))
172 ? y_intercept_ > other.y_intercept_
173 : (slope_ - other.slope_) * x + y_intercept_ > other.y_intercept_;
176 // Remove redundant empty buildings from the skyline.
177 // If there are two adjacent empty buildings, they can be
180 Skyline::normalize ()
182 bool last_empty = false;
183 list<Building>::iterator i;
185 for (i = buildings_.begin (); i != buildings_.end (); i++)
187 if (last_empty && i->y_intercept_ == -infinity_f)
189 list<Building>::iterator last = i;
191 last->end_ = i->end_;
192 buildings_.erase (i);
195 last_empty = (i->y_intercept_ == -infinity_f);
198 assert (buildings_.front ().start_ == -infinity_f);
199 assert (buildings_.back ().end_ == infinity_f);
203 Skyline::internal_merge_skyline (list<Building> *sb, list<Building> *sc,
204 list<Building> *const result) const
206 if (sb->empty () || sc->empty ())
208 programming_error ("tried to merge an empty skyline");
212 Building b = sb->front ();
213 for (; !sc->empty (); sc->pop_front ())
215 /* Building b is continuing from the previous pass through the loop.
216 Building c is newly-considered, and starts no earlier than b started.
217 The comments draw b as if its roof had zero slope ----.
218 with dashes where b lies above c.
219 The roof of c could rise / or fall \ through the roof of b,
220 or the vertical sides | of c could intersect the roof of b. */
221 Building c = sc->front ();
222 if (b.end_ < c.end_) /* finish with b */
224 if (b.end_ <= b.start_) /* we are already finished with b */
226 else if (c.above (b, c.start_)) /* -| . | */
230 if (m.end_ > m.start_)
231 result->push_back (m);
232 if (b.above (c, b.end_)) /* -|\--. */
235 n.end_ = b.start_ = b.intersection_x (c);
236 result->push_back (n);
237 result->push_back (b);
242 if (c.above (b, b.end_)) /* ---/ . | */
243 b.end_ = b.intersection_x (c);
246 result->push_back (b);
248 /* 'c' continues further, so move it into 'b' for the next pass. */
252 else /* b.end_ > c.end_ so finish with c */
254 if (c.above (b, c.start_)) /* -| |---. */
258 if (m.end_ > m.start_)
259 result->push_back (m);
260 if (b.above (c, c.end_)) /* -| \---. */
261 c.end_ = b.intersection_x (c);
263 else if (c.above (b, c.end_)) /* ---/|--. */
266 c.start_ = m.end_ = b.intersection_x (c);
267 result->push_back (m);
269 else /* c is completely hidden by b */
271 result->push_back (c);
275 if (b.end_ > b.start_)
276 result->push_back (b);
280 empty_skyline (list<Building> *const ret)
282 ret->push_front (Building (-infinity_f, -infinity_f, -infinity_f, infinity_f));
286 Given Building 'b', build a skyline containing only that building.
289 single_skyline (Building b, list<Building> *const ret)
291 assert (b.end_ >= b.start_);
293 if (b.start_ != -infinity_f)
294 ret->push_back (Building (-infinity_f, -infinity_f,
295 -infinity_f, b.start_));
297 if (b.end_ != infinity_f)
298 ret->push_back (Building (b.end_, -infinity_f,
299 -infinity_f, infinity_f));
302 /* remove a non-overlapping set of boxes from BOXES and build a skyline
304 static list<Building>
305 non_overlapping_skyline (list<Building> *const buildings)
307 list<Building> result;
308 Real last_end = -infinity_f;
309 Building last_building (-infinity_f, -infinity_f, -infinity_f, infinity_f);
310 list<Building>::iterator i = buildings->begin ();
311 while (i != buildings->end ())
314 Real y1 = i->height (i->start_);
316 Real y2 = i->height (i->end_);
318 // Drop buildings that will obviously have no effect.
319 if (last_building.height (x1) >= y1
320 && last_building.end_ >= x2
321 && last_building.height (x2) >= y2)
323 list<Building>::iterator j = i++;
324 buildings->erase (j);
334 // Insert empty Buildings into any gaps. (TODO: is this needed? -KOH)
336 result.push_back (Building (last_end, -infinity_f, -infinity_f, x1));
338 result.push_back (*i);
342 list<Building>::iterator j = i++;
343 buildings->erase (j);
346 if (last_end < infinity_f)
347 result.push_back (Building (last_end, -infinity_f, -infinity_f, infinity_f));
351 class LessThanBuilding
354 bool operator () (Building const &b1, Building const &b2)
356 return b1.start_ < b2.start_
357 || (b1.start_ == b2.start_ && b1.height (b1.start_) > b2.height (b1.start_));
362 BUILDINGS is a list of buildings, but they could be overlapping
363 and in any order. The returned list of buildings is ordered and non-overlapping.
366 Skyline::internal_build_skyline (list<Building> *buildings) const
368 vsize size = buildings->size ();
372 list<Building> result;
373 empty_skyline (&result);
378 list<Building> result;
379 single_skyline (buildings->front (), &result);
383 deque<list<Building> > partials;
384 buildings->sort (LessThanBuilding ());
385 while (!buildings->empty ())
386 partials.push_back (non_overlapping_skyline (buildings));
388 /* we'd like to say while (partials->size () > 1) but that's O (n).
389 Instead, we exit in the middle of the loop */
390 while (!partials.empty ())
392 list<Building> merged;
393 list<Building> one = partials.front ();
394 partials.pop_front ();
395 if (partials.empty ())
398 list<Building> two = partials.front ();
399 partials.pop_front ();
400 internal_merge_skyline (&one, &two, &merged);
401 partials.push_back (merged);
404 return list<Building> ();
410 empty_skyline (&buildings_);
413 Skyline::Skyline (Direction sky)
416 empty_skyline (&buildings_);
420 Build skyline from a set of boxes.
422 Boxes should be non-empty on both axes. Otherwise, they will be ignored
424 Skyline::Skyline (vector<Box> const &boxes, Axis horizon_axis, Direction sky)
426 list<Building> buildings;
429 for (vsize i = 0; i < boxes.size (); i++)
430 if (!boxes[i].is_empty (X_AXIS)
431 && !boxes[i].is_empty (Y_AXIS))
432 buildings.push_front (Building (boxes[i], horizon_axis, sky));
434 buildings_ = internal_build_skyline (&buildings);
439 build skyline from a set of line segments.
441 Segments can be articulated from left to right or right to left.
442 In the case of the latter, they will be stored internally as left to right.
444 Skyline::Skyline (vector<Drul_array<Offset> > const &segments, Axis horizon_axis, Direction sky)
446 list<Building> buildings;
449 for (vsize i = 0; i < segments.size (); i++)
451 Drul_array<Offset> const &seg = segments[i];
452 Offset left = seg[LEFT];
453 Offset right = seg[RIGHT];
454 if (left[horizon_axis] > right[horizon_axis])
457 Real x1 = left[horizon_axis];
458 Real x2 = right[horizon_axis];
459 Real y1 = left[other_axis (horizon_axis)] * sky;
460 Real y2 = right[other_axis (horizon_axis)] * sky;
463 buildings.push_back (Building (x1, y1, y2, x2));
466 buildings_ = internal_build_skyline (&buildings);
470 Skyline::Skyline (vector<Skyline_pair> const &skypairs, Direction sky)
474 deque<Skyline> partials;
475 for (vsize i = 0; i < skypairs.size (); i++)
476 partials.push_back (Skyline ((skypairs[i])[sky]));
478 while (partials.size () > 1)
480 Skyline one = partials.front ();
481 partials.pop_front ();
482 Skyline two = partials.front ();
483 partials.pop_front ();
486 partials.push_back (one);
489 if (partials.size ())
490 buildings_.swap (partials.front ().buildings_);
495 Skyline::Skyline (Box const &b, Axis horizon_axis, Direction sky)
498 if (!b.is_empty (X_AXIS) && !b.is_empty (Y_AXIS))
500 Building front (b, horizon_axis, sky);
501 single_skyline (front, &buildings_);
507 Skyline::merge (Skyline const &other)
509 assert (sky_ == other.sky_);
511 if (other.is_empty ())
516 buildings_ = other.buildings_;
520 list<Building> other_bld (other.buildings_);
521 list<Building> my_bld;
522 my_bld.splice (my_bld.begin (), buildings_);
523 internal_merge_skyline (&other_bld, &my_bld, &buildings_);
528 Skyline::insert (Box const &b, Axis a)
530 list<Building> other_bld;
531 list<Building> my_bld;
533 if (isnan (b[other_axis (a)][LEFT])
534 || isnan (b[other_axis (a)][RIGHT]))
536 programming_error ("insane box for skyline");
540 /* do the same filtering as in Skyline (vector<Box> const&, etc.) */
541 if (b.is_empty (X_AXIS) || b.is_empty (Y_AXIS))
544 my_bld.splice (my_bld.begin (), buildings_);
545 single_skyline (Building (b, a, sky_), &other_bld);
546 internal_merge_skyline (&other_bld, &my_bld, &buildings_);
551 Skyline::raise (Real r)
553 list<Building>::iterator end = buildings_.end ();
554 for (list<Building>::iterator i = buildings_.begin (); i != end; i++)
555 i->y_intercept_ += sky_ * r;
559 Skyline::shift (Real s)
561 list<Building>::iterator end = buildings_.end ();
562 for (list<Building>::iterator i = buildings_.begin (); i != end; i++)
566 i->y_intercept_ -= s * i->slope_;
571 Skyline::distance (Skyline const &other, Real horizon_padding) const
574 return internal_distance (other, horizon_padding, &dummy);
578 Skyline::touching_point (Skyline const &other, Real horizon_padding) const
581 internal_distance (other, horizon_padding, &touch);
586 Skyline::internal_distance (Skyline const &other, Real horizon_padding, Real *touch_point) const
588 if (horizon_padding == 0.0)
589 return internal_distance (other, touch_point);
591 // Note that it is not necessary to build a padded version of other,
592 // because the same effect can be achieved just by doubling horizon_padding.
593 Skyline padded_this = padded (horizon_padding);
594 return padded_this.internal_distance (other, touch_point);
598 Skyline::padded (Real horizon_padding) const
600 if (horizon_padding < 0.0)
601 warning ("Cannot have negative horizon padding. Junking.");
603 if (horizon_padding <= 0.0)
606 list<Building> pad_buildings;
607 for (list<Building>::const_iterator i = buildings_.begin (); i != buildings_.end (); ++i)
609 if (i->start_ > -infinity_f)
611 Real height = i->height (i->start_);
612 if (height > -infinity_f)
614 // Add the sloped building that pads the left side of the current building.
615 Real start = i->start_ - 2 * horizon_padding;
616 Real end = i->start_ - horizon_padding;
617 pad_buildings.push_back (Building (start, height - horizon_padding, height, end));
619 // Add the flat building that pads the left side of the current building.
620 start = i->start_ - horizon_padding;
622 pad_buildings.push_back (Building (start, height, height, end));
626 if (i->end_ < infinity_f)
628 Real height = i->height (i->end_);
629 if (height > -infinity_f)
631 // Add the flat building that pads the right side of the current building.
632 Real start = i->end_;
633 Real end = start + horizon_padding;
634 pad_buildings.push_back (Building (start, height, height, end));
636 // Add the sloped building that pads the right side of the current building.
638 end += horizon_padding;
639 pad_buildings.push_back (Building (start, height, height - horizon_padding, end));
644 // The buildings may be overlapping, so resolve that.
645 list<Building> pad_skyline = internal_build_skyline (&pad_buildings);
647 // Merge the padding with the original, to make a new skyline.
648 Skyline padded (sky_);
649 list<Building> my_buildings = buildings_;
650 padded.buildings_.clear ();
651 internal_merge_skyline (&pad_skyline, &my_buildings, &padded.buildings_);
658 Skyline::internal_distance (Skyline const &other, Real *touch_point) const
660 assert (sky_ == -other.sky_);
662 list<Building>::const_iterator i = buildings_.begin ();
663 list<Building>::const_iterator j = other.buildings_.begin ();
665 Real dist = -infinity_f;
666 Real start = -infinity_f;
667 Real touch = -infinity_f;
668 while (i != buildings_.end () && j != other.buildings_.end ())
670 Real end = min (i->end_, j->end_);
671 Real start_dist = i->height (start) + j->height (start);
672 Real end_dist = i->height (end) + j->height (end);
673 dist = max (dist, max (start_dist, end_dist));
675 if (end_dist == dist)
677 else if (start_dist == dist)
680 if (i->end_ <= j->end_)
687 *touch_point = touch;
692 Skyline::height (Real airplane) const
694 assert (!isinf (airplane));
696 list<Building>::const_iterator i;
697 for (i = buildings_.begin (); i != buildings_.end (); i++)
699 if (i->end_ >= airplane)
700 return sky_ * i->height (airplane);
708 Skyline::max_height () const
710 Real ret = -infinity_f;
712 list<Building>::const_iterator i;
713 for (i = buildings_.begin (); i != buildings_.end (); ++i)
715 ret = max (ret, i->height (i->start_));
716 ret = max (ret, i->height (i->end_));
723 Skyline::direction () const
729 Skyline::left () const
731 for (list<Building>::const_iterator i (buildings_.begin ());
732 i != buildings_.end (); i++)
733 if (i->y_intercept_ > -infinity_f)
740 Skyline::right () const
742 for (list<Building>::const_reverse_iterator i (buildings_.rbegin ());
743 i != buildings_.rend (); ++i)
744 if (i->y_intercept_ > -infinity_f)
751 Skyline::max_height_position () const
754 s.set_minimum_height (0);
755 return touching_point (s);
759 Skyline::set_minimum_height (Real h)
762 s.buildings_.front ().y_intercept_ = h * sky_;
767 Skyline::to_points (Axis horizon_axis) const
771 Real start = -infinity_f;
772 for (list<Building>::const_iterator i (buildings_.begin ());
773 i != buildings_.end (); i++)
775 out.push_back (Offset (start, sky_ * i->height (start)));
776 out.push_back (Offset (i->end_, sky_ * i->height (i->end_)));
780 if (horizon_axis == Y_AXIS)
781 for (vsize i = 0; i < out.size (); i++)
782 out[i] = out[i].swapped ();
788 Skyline::is_empty () const
790 if (!buildings_.size ())
792 Building b = buildings_.front ();
793 return b.end_ == infinity_f && b.y_intercept_ == -infinity_f;
800 empty_skyline (&buildings_);
803 /****************************************************************/
805 const char Skyline::type_p_name_[] = "ly:skyline?";
807 MAKE_SCHEME_CALLBACK_WITH_OPTARGS (Skyline, get_touching_point, 3, 1, "")
809 Skyline::get_touching_point (SCM skyline_scm, SCM other_skyline_scm, SCM horizon_padding_scm)
811 LY_ASSERT_SMOB (Skyline, other_skyline_scm, 1);
813 Real horizon_padding = 0;
814 if (!SCM_UNBNDP (horizon_padding_scm))
816 LY_ASSERT_TYPE (scm_is_number, horizon_padding_scm, 3);
817 horizon_padding = scm_to_double (horizon_padding_scm);
820 Skyline *skyline = unsmob<Skyline> (skyline_scm);
821 Skyline *other_skyline = unsmob<Skyline> (other_skyline_scm);
822 return scm_from_double (skyline->touching_point (*other_skyline, horizon_padding));
825 MAKE_SCHEME_CALLBACK_WITH_OPTARGS (Skyline, get_distance, 3, 1, "")
827 Skyline::get_distance (SCM skyline_scm, SCM other_skyline_scm, SCM horizon_padding_scm)
829 LY_ASSERT_SMOB (Skyline, other_skyline_scm, 1);
831 Real horizon_padding = 0;
832 if (!SCM_UNBNDP (horizon_padding_scm))
834 LY_ASSERT_TYPE (scm_is_number, horizon_padding_scm, 3);
835 horizon_padding = scm_to_double (horizon_padding_scm);
838 Skyline *skyline = unsmob<Skyline> (skyline_scm);
839 Skyline *other_skyline = unsmob<Skyline> (other_skyline_scm);
840 return scm_from_double (skyline->distance (*other_skyline, horizon_padding));
843 MAKE_SCHEME_CALLBACK (Skyline, get_max_height, 1)
845 Skyline::get_max_height (SCM skyline_scm)
847 return scm_from_double (unsmob<Skyline> (skyline_scm)->max_height ());
850 MAKE_SCHEME_CALLBACK (Skyline, get_max_height_position, 1)
852 Skyline::get_max_height_position (SCM skyline_scm)
854 return scm_from_double (unsmob<Skyline> (skyline_scm)->max_height_position ());
857 MAKE_SCHEME_CALLBACK (Skyline, get_height, 2)
859 Skyline::get_height (SCM skyline_scm, SCM x_scm)
861 Real x = robust_scm2double (x_scm, 0.0);
862 return scm_from_double (unsmob<Skyline> (skyline_scm)->height (x));
865 LY_DEFINE (ly_skyline_empty_p, "ly:skyline-empty?",
867 "Return whether @var{sky} is empty.")
869 Skyline *s = unsmob<Skyline> (sky);
870 LY_ASSERT_SMOB (Skyline, sky, 1);
871 return scm_from_bool (s->is_empty ());