1 /* skyline.cc -- implement the Skyline class
3 source file of the GNU LilyPond music typesetter
5 (c) 2006--2007 Joe Neeman <joeneeman@gmail.com>
11 #include "ly-smobs.icc"
13 /* A skyline is a sequence of non-overlapping buildings: something like
23 Each building has a starting position, and ending position, a starting
24 height and an ending height.
26 The following invariants are observed:
27 - the start of the first building is at -infinity
28 - the end of the last building is at infinity
29 - if a building has infinite length (ie. the first and last buildings),
30 then its starting height and ending height are equal
31 - the end of one building is the same as the beginning of the next
34 We also allow skylines to point down (the structure is exactly the same,
35 but we think of the part above the line as being filled with mass and the
36 part below as being empty). ::distance finds the minimum distance between
37 an UP skyline and a DOWN skyline.
39 Note that we store DOWN skylines upside-down. That is, in order to compare
40 a DOWN skyline with an UP skyline, we need to flip the DOWN skyline first.
41 This means that the merging routine doesn't need to be aware of direction,
42 but the distance routine does.
50 typedef list<Skyline_point> Skyline;
57 this is a cleaner representation, as it doesn't duplicate the X, and
58 doesn't need bogus buildings at infinity --hwn.
61 * All the messing around with EPS is very fishy. There are no
62 complicated numerical algorithms involved, so EPS should not be
73 approx_equal (Real x, Real y)
75 return abs (x - y) < EPS || (isinf (x) && isinf (y) && ((x > 0) == (y > 0)));
79 approx_greater_than (Real x, Real y)
85 approx_less_than (Real x, Real y)
91 approx_less_equal (Real x, Real y)
97 approx_greater_equal (Real x, Real y)
103 Skyline::print () const
105 for (list<Building>::const_iterator i = buildings_.begin ();
106 i != buildings_.end (); i++)
113 is_legal_skyline (list<Building> const &buildings)
115 list<Building>::const_iterator i;
116 Real last_x = -infinity_f;
117 for (i = buildings.begin (); i != buildings.end (); i++)
119 if (i->iv_[LEFT] != last_x)
121 last_x = i->iv_[RIGHT];
122 if (isinf (i->iv_.length ()) && i->height_[LEFT] != i->height_[RIGHT])
125 return last_x == infinity_f;
128 Building::Building (Real start, Real start_height, Real end_height, Real end)
131 height_[LEFT] = start_height;
132 height_[RIGHT] = end_height;
134 if (isinf (start) || isinf (end))
135 assert (start_height == end_height);
140 Building::Building (Box const &b, Real horizon_padding, Axis horizon_axis, Direction sky)
142 Real height = sky * b[other_axis (horizon_axis)][sky];
144 iv_ = b[horizon_axis];
145 iv_.widen (horizon_padding + EPS);
146 height_[LEFT] = height;
147 height_[RIGHT] = height;
154 Building::precompute ()
156 slope_ = (height_[RIGHT] - height_[LEFT]) / (iv_.length ());
157 if (height_[LEFT] == height_[RIGHT]) /* in case they're both infinity */
160 assert (!isinf (slope_) && !isnan (slope_));
162 if (isinf (iv_[START]))
164 assert (slope_ == 0);
165 y_intercept_ = height_[LEFT];
168 y_intercept_ = height_[LEFT] - slope_ * iv_[START];
172 Building::height (Real x) const
175 return (x > 0) ? height_[RIGHT] : height_[LEFT];
176 return slope_*x + y_intercept_;
180 Building::print () const
182 printf ("X[%f,%f] -> Y[%f,%f]\n",
183 iv_[LEFT], iv_[RIGHT],
184 height_[LEFT], height_[RIGHT]);
188 Building::intersection_x (Building const &other) const
190 return (y_intercept_ - other.y_intercept_) / (other.slope_ - slope_);
194 Building::leading_part (Real chop)
196 assert (chop > iv_[LEFT] && chop <= iv_[RIGHT] && !approx_equal (chop, iv_[LEFT]));
198 height_[RIGHT] = height (chop);
202 Building::sloped_neighbour (Real horizon_padding, Direction d) const
205 Real right = iv_[d] + d * horizon_padding;
206 Real left_height = height_[d];
207 Real right_height = height_[d] - horizon_padding;
211 swap (left_height, right_height);
213 return Building (left, left_height, right_height, right);
217 Building::sane () const
219 return approx_less_than (iv_[LEFT], iv_[RIGHT])
220 && !isinf (height_[RIGHT])
221 && !isinf (height_[LEFT]);
225 skyline_trailing_part (list<Building> *sky, Real x)
227 if (approx_equal (x, sky->front ().iv_[RIGHT]))
230 assert (x < sky->front ().iv_[RIGHT]);
234 sky->front ().iv_[LEFT] = x;
235 sky->front ().height_[LEFT] = sky->front ().height (x);
240 Building::conceals_beginning (Building const &other) const
243 Real h = other.height (iv_[LEFT]);
244 if (approx_equal (height_[LEFT], h))
245 w = slope_ > other.slope_;
246 else if (height_[LEFT] > h)
255 Building::conceals (Building const &other) const
257 assert (iv_[LEFT] <= other.iv_[LEFT]);
258 return (iv_[RIGHT] >= other.iv_[RIGHT])
259 && approx_greater_equal (height (other.iv_[LEFT]), other.height_[LEFT])
260 && approx_greater_equal (height (other.iv_[RIGHT]), other.height_[RIGHT]);
264 Skyline::internal_merge_skyline (list<Building> *s1, list<Building> *s2,
265 list<Building> *const result)
267 while (!s1->empty ())
269 if (s2->front ().conceals_beginning (s1->front ()))
272 Building b = s1->front ();
273 while (!s2->empty () && b.conceals (s2->front ()))
277 result->push_front (b);
281 /* s2 either intersects with b or it ends after b */
282 Real end = infinity_f;
283 Real s2_start_height = s2->front ().height_[LEFT];
284 Real s2_end_height = s2->front ().height_[RIGHT];
285 Real s1_start_height = b.height (s2->front ().iv_[LEFT]);
286 Real s1_end_height = b.height (s2->front ().iv_[RIGHT]);
287 if (approx_greater_than (s2_start_height, s1_start_height))
288 end = s2->front ().iv_[LEFT];
289 else if (approx_greater_than (s2_end_height, s1_end_height))
290 end = b.intersection_x (s2->front ());
291 end = min (end, b.iv_[RIGHT]);
293 b.leading_part (end);
294 result->push_front (b);
296 skyline_trailing_part (s1, end);
297 skyline_trailing_part (s2, end);
303 empty_skyline (list<Building> *const ret)
305 ret->push_front (Building (-infinity_f, -infinity_f, -infinity_f, infinity_f));
309 single_skyline (Building b, Real horizon_padding, list<Building> *const ret)
311 b.iv_.widen (horizon_padding);
313 if (!isinf (b.iv_[RIGHT]))
314 ret->push_front (Building (b.iv_[RIGHT], -infinity_f,
315 -infinity_f, infinity_f));
316 if (horizon_padding > 0 && !isinf (b.iv_.length ()))
317 ret->push_front (b.sloped_neighbour (horizon_padding, RIGHT));
319 if (b.iv_[RIGHT] > b.iv_[LEFT])
322 if (horizon_padding > 0 && !isinf (b.iv_.length ()))
323 ret->push_front (b.sloped_neighbour (horizon_padding, LEFT));
324 if (!isinf (b.iv_[LEFT]))
325 ret->push_front (Building (-infinity_f, -infinity_f,
326 -infinity_f, b.iv_[LEFT]));
329 /* remove a non-overlapping set of buildings from BUILDINGS and build a skyline
331 static list<Building>
332 non_overlapping_skyline (list<Building> *const buildings)
334 list<Building> result;
335 Real last_end = -infinity_f;
336 list<Building>::iterator i = buildings->begin ();
337 while (i != buildings->end ())
339 if (approx_less_than (i->iv_[LEFT], last_end))
345 if (approx_greater_than (i->iv_[LEFT], last_end))
346 result.push_back (Building (last_end, -infinity_f, -infinity_f, i->iv_[LEFT]));
348 i->iv_[LEFT] = last_end;
350 last_end = i->iv_[RIGHT];
351 list<Building>::iterator j = i;
353 result.splice (result.end (), *buildings, j);
355 if (last_end < infinity_f)
356 result.push_back (Building (last_end, -infinity_f, -infinity_f, infinity_f));
357 assert (is_legal_skyline (result));
362 Skyline::internal_build_skyline (list<Building> *buildings)
364 vsize size = buildings->size ();
368 list<Building> result;
369 empty_skyline (&result);
374 list<Building> result;
375 single_skyline (buildings->front (), 0, &result);
379 deque<list<Building> > partials;
381 while (!buildings->empty ())
382 partials.push_back (non_overlapping_skyline (buildings));
384 /* we'd like to say while (partials->size () > 1) but that's O (n).
385 Instead, we exit in the middle of the loop */
386 while (!partials.empty ())
388 list<Building> merged;
389 list<Building> one = partials.front ();
390 partials.pop_front ();
391 if (partials.empty ())
394 list<Building> two = partials.front ();
395 partials.pop_front ();
396 internal_merge_skyline (&one, &two, &merged);
397 partials.push_back (merged);
400 return list<Building> ();
406 empty_skyline (&buildings_);
409 Skyline::Skyline (Skyline const &src)
413 for (list<Building>::const_iterator i = src.buildings_.begin ();
414 i != src.buildings_.end (); i++)
416 buildings_.push_back (Building ((*i)));
420 Skyline::Skyline (Direction sky)
423 empty_skyline (&buildings_);
427 build skyline from a set of boxes. If horizon_padding > 0, expand all the boxes
428 by that amount and add 45-degree sloped boxes to the edges of each box (of
429 width horizon_padding). That is, the total amount of horizontal expansion is
430 horizon_padding*4, half of which is sloped and half of which is flat.
432 Boxes should have fatness in the horizon_axis (after they are expanded by
433 horizon_padding), otherwise they are ignored.
435 Skyline::Skyline (vector<Box> const &boxes, Real horizon_padding, Axis horizon_axis, Direction sky)
437 list<Building> bldgs;
440 for (vsize i = 0; i < boxes.size (); i++)
442 Building front (boxes[i], horizon_padding, horizon_axis, sky);
445 bldgs.push_front (front);
446 if (horizon_padding > 0 && !isinf (front.iv_.length ()))
448 bldgs.push_front (front.sloped_neighbour (horizon_padding, LEFT));
449 bldgs.push_front (front.sloped_neighbour (horizon_padding, RIGHT));
454 buildings_ = internal_build_skyline (&bldgs);
455 assert (is_legal_skyline (buildings_));
458 Skyline::Skyline (Box const &b, Real horizon_padding, Axis horizon_axis, Direction sky)
461 Building front (b, 0, horizon_axis, sky);
462 single_skyline (front, horizon_padding, &buildings_);
466 Skyline::merge (Skyline const &other)
468 assert (sky_ == other.sky_);
470 list<Building> other_bld (other.buildings_);
471 list<Building> my_bld;
472 my_bld.splice (my_bld.begin (), buildings_);
473 internal_merge_skyline (&other_bld, &my_bld, &buildings_);
474 assert (is_legal_skyline (buildings_));
478 Skyline::insert (Box const &b, Real horizon_padding, Axis a)
480 list<Building> other_bld;
481 list<Building> my_bld;
483 my_bld.splice (my_bld.begin (), buildings_);
484 single_skyline (Building (b, 0, a, sky_), horizon_padding, &other_bld);
485 internal_merge_skyline (&other_bld, &my_bld, &buildings_);
486 assert (is_legal_skyline (buildings_));
490 Skyline::raise (Real r)
492 list<Building>::iterator end = buildings_.end ();
493 for (list<Building>::iterator i = buildings_.begin (); i != end; i++)
495 i->height_[LEFT] += sky_ * r;
496 i->height_[RIGHT] += sky_ * r;
497 i->y_intercept_ += sky_ * r;
499 assert (is_legal_skyline (buildings_));
503 Skyline::shift (Real r)
505 list<Building>::iterator end = buildings_.end ();
506 for (list<Building>::iterator i = buildings_.begin (); i != end; i++)
514 Skyline::distance (Skyline const &other) const
516 assert (sky_ == -other.sky_);
517 list<Building>::const_iterator i = buildings_.begin ();
518 list<Building>::const_iterator j = other.buildings_.begin ();
520 Real dist = -infinity_f;
521 while (i != buildings_.end () && j != other.buildings_.end ())
523 Interval iv = intersection (i->iv_, j->iv_);
524 dist = max (dist, max (i->height (iv[LEFT]) + j->height (iv[LEFT]),
525 i->height (iv[RIGHT]) + j->height (iv[RIGHT])));
526 if (i->iv_[RIGHT] <= j->iv_[RIGHT])
535 Skyline::height (Real airplane) const
537 assert (!isinf (airplane));
539 list<Building>::const_iterator i;
540 for (i = buildings_.begin (); i != buildings_.end (); i++)
542 if (i->iv_[RIGHT] >= airplane)
543 return sky_ * i->height (airplane);
551 Skyline::max_height () const
554 s.set_minimum_height (0);
555 return sky_ * distance (s);
559 Skyline::set_minimum_height (Real h)
562 s.buildings_.front ().height_[LEFT] = h * sky_;
563 s.buildings_.front ().height_[RIGHT] = h * sky_;
564 s.buildings_.front ().y_intercept_ = h * sky_;
570 Skyline::to_points () const
574 for (list<Building>::const_iterator i (buildings_.begin ());
575 i != buildings_.end (); i++)
577 if (!isinf (i->iv_[LEFT]) && !isinf (i->height_[LEFT]))
578 out.push_back (Offset (i->iv_[LEFT], sky_ * i->height_[LEFT]));
579 if (!isinf (i->iv_[RIGHT]) && !isinf (i->height_[RIGHT]))
580 out.push_back (Offset (i->iv_[RIGHT], sky_ * i->height_[RIGHT]));
586 Skyline::is_empty () const
588 return buildings_.empty ();
591 Skyline_pair::Skyline_pair ()
592 : skylines_ (Skyline (DOWN), Skyline (UP))
596 Skyline_pair::Skyline_pair (vector<Box> const &boxes, Real padding, Axis a)
597 : skylines_ (Skyline (boxes, padding, a, DOWN), Skyline (boxes, padding, a, UP))
601 Skyline_pair::Skyline_pair (Box const &b, Real padding, Axis a)
602 : skylines_ (Skyline (b, padding, a, DOWN), Skyline (b, padding, a, UP))
607 Skyline_pair::raise (Real r)
609 skylines_[UP].raise (r);
610 skylines_[DOWN].raise (r);
614 Skyline_pair::shift (Real r)
616 skylines_[UP].shift (r);
617 skylines_[DOWN].shift (r);
621 Skyline_pair::insert (Box const &b, Real padding, Axis a)
623 skylines_[UP].insert (b, padding, a);
624 skylines_[DOWN].insert (b, padding, a);
628 Skyline_pair::merge (Skyline_pair const &other)
630 skylines_[UP].merge (other[UP]);
631 skylines_[DOWN].merge (other[DOWN]);
635 Skyline_pair::is_empty () const
637 return skylines_[UP].is_empty ()
638 && skylines_[DOWN].is_empty ();
642 Skyline_pair::operator [] (Direction d)
648 Skyline_pair::operator [] (Direction d) const
653 /****************************************************************/
656 IMPLEMENT_SIMPLE_SMOBS (Skyline);
657 IMPLEMENT_TYPE_P (Skyline, "ly:skyline?");
658 IMPLEMENT_DEFAULT_EQUAL_P (Skyline);
660 IMPLEMENT_SIMPLE_SMOBS (Skyline_pair);
661 IMPLEMENT_TYPE_P (Skyline_pair, "ly:skyline-pair?");
662 IMPLEMENT_DEFAULT_EQUAL_P (Skyline_pair);
665 Skyline::mark_smob (SCM)
667 ASSERT_LIVE_IS_ALLOWED ();
672 Skyline::print_smob (SCM s, SCM port, scm_print_state *)
674 Skyline *r = (Skyline *) SCM_CELL_WORD_1 (s);
677 scm_puts ("#<Skyline>", port);
683 Skyline_pair::mark_smob (SCM)
689 Skyline_pair::print_smob (SCM s, SCM port, scm_print_state *)
691 Skyline_pair *r = (Skyline_pair *) SCM_CELL_WORD_1 (s);
694 scm_puts ("#<Skyline-pair>", port);