1 /* skyline.cc -- implement the Skyline class
3 source file of the GNU LilyPond music typesetter
5 (c) 2006 Joe Neeman <joeneeman@gmail.com>
10 #include "line-interface.hh"
12 /* A skyline is a sequence of non-overlapping buildings: something like
22 Each building has a starting position, and ending position, a starting
23 height and an ending height.
25 The following invariants are observed:
26 - the start of the first building is at -infinity
27 - the end of the last building is at infinity
28 - if a building has infinite length (ie. the first and last buildings),
29 then its starting height and ending height are equal
30 - the end of one building is the same as the beginning of the next
33 We also allow skylines to point down (the structure is exactly the same,
34 but we think of the part above the line as being filled with mass and the
35 part below as being empty). ::distance finds the minimum distance between
36 an UP skyline and a DOWN skyline.
38 Note that we store DOWN skylines upside-down. That is, in order to compare
39 a DOWN skyline with an UP skyline, we need to flip the DOWN skyline first.
40 This means that the merging routine doesn't need to be aware of direction,
41 but the distance routine does.
47 equal (Real x, Real y)
49 return abs (x - y) < EPS || (isinf (x) && isinf (y) && ((x > 0) == (y > 0)));
53 Skyline::is_legal_skyline () const
55 list<Building>::const_iterator i;
56 Real last_x = -infinity_f;
57 Real last_h = -infinity_f;
58 for (i = buildings_.begin (); i != buildings_.end (); i++)
60 if (i->iv_[LEFT] != last_x)
62 if (i != buildings_.begin () && !equal (i->start_height_, last_h))
64 last_x = i->iv_[RIGHT];
65 last_h = i->end_height_;
67 return last_x == infinity_f;
70 Building::Building (Real start, Real start_height, Real end_height,
71 Real end, Real max_slope)
74 start_height_ = start_height;
75 end_height_ = end_height;
78 assert (isinf (start_height) || start_height == end_height);
80 assert (isinf (end_height) || start_height == end_height);
82 precompute (max_slope);
86 Building::precompute (Real max_slope)
88 slope_ = (end_height_ - start_height_) / (iv_.length());
89 if (start_height_ == end_height_)
91 if (isinf (slope_) || isnan (slope_))
92 slope_ = max_slope * (start_height_ < end_height_ ? 1 : -1);
93 assert (abs (slope_) <= max_slope);
95 if (isinf (iv_[START]))
97 if (isinf (iv_[STOP]))
98 zero_height_ = start_height_;
100 zero_height_ = end_height_ - slope_ * iv_[STOP];
103 zero_height_ = start_height_ - slope_ * iv_[START];
107 Building::height (Real x) const
110 return (x > 0) ? end_height_ : start_height_;
111 return slope_*x + zero_height_;
115 Building::intersection (Building const &other) const
117 return (zero_height_ - other.zero_height_) / (other.slope_ - slope_);
121 Building::leading_part (Real chop, Real h)
123 assert (chop > iv_[LEFT] && chop <= iv_[RIGHT] && !equal (chop, iv_[LEFT]));
124 assert (equal (h, height (chop)));
130 skyline_trailing_part (list<Building> *sky, Real x)
132 if (equal (x, sky->front ().iv_[RIGHT]))
135 assert (x < sky->front ().iv_[RIGHT]);
139 sky->front ().iv_[LEFT] = x;
140 sky->front ().start_height_ = sky->front ().height (x);
145 Building::obstructs (Building const &other) const
147 if (equal (intersection (other), iv_[LEFT]) || equal (start_height_, other.start_height_))
148 return slope_ > other.slope_ || (slope_ == other.slope_ && zero_height_ > other.zero_height_);
149 return start_height_ > other.start_height_;
153 Skyline::internal_merge_skyline (list<Building> *s1, list<Building> *s2,
154 list<Building> *const result)
156 while (!s1->empty ())
158 if (s2->front ().obstructs (s1->front ()))
161 Building b = s1->front ();
162 while (s2->front ().iv_[RIGHT] < b.iv_[RIGHT]
163 && s2->front ().end_height_ <= b.height (s2->front ().iv_[RIGHT]) + EPS)
166 /* the front of s2 either intersects with b or it ends after b */
167 Real end = infinity_f;
168 Real s2_end_height = s2->front ().end_height_;
169 Real s1_end_height = b.height (s2->front ().iv_[RIGHT]);
170 if (s2_end_height > s1_end_height + EPS)
171 end = b.intersection (s2->front ());
172 end = min (end, b.iv_[RIGHT]);
173 Real height = b.height (end);
175 b.leading_part (end, height);
176 result->push_front (b);
178 skyline_trailing_part (s1, end);
180 s1->front ().start_height_ = height;
181 skyline_trailing_part (s2, end);
187 empty_skyline (list<Building> *const ret)
189 ret->push_front (Building (-infinity_f, -infinity_f, -infinity_f, infinity_f, 0));
193 single_skyline (Building const &b, list<Building> *const ret, Real max_slope)
195 if (!isinf (b.iv_[RIGHT]))
196 ret->push_front (Building (b.iv_[RIGHT], b.end_height_, -infinity_f, infinity_f, max_slope));
198 if (!isinf (b.iv_[LEFT]))
199 ret->push_front (Building (-infinity_f, -infinity_f, b.start_height_, b.iv_[LEFT], max_slope));
203 Skyline::internal_build_skyline (list<Building> *buildings, list<Building> *const result)
205 vsize size = buildings->size ();
209 empty_skyline (result);
214 single_skyline (buildings->front (), result, max_slope_);
218 list<Building> right_half;
219 list<Building>::iterator i = buildings->begin ();
221 for (vsize s = 0; s < size/2; s++)
223 right_half.splice (right_half.end (), *buildings, i, buildings->end ());
225 list<Building> right;
227 internal_build_skyline (&right_half, &right);
228 internal_build_skyline (buildings, &left);
229 internal_merge_skyline (&right, &left, result);
236 empty_skyline (&buildings_);
239 Skyline::Skyline (Direction sky)
243 empty_skyline (&buildings_);
247 Skyline::Skyline (vector<Box> const &boxes, Axis a, Direction sky)
249 list<Building> bldgs;
253 for (vsize i = 0; i < boxes.size (); i++)
255 Interval iv = boxes[i][a];
256 Real height = sky * boxes[i][other_axis (a)][sky];
257 if (!iv.is_empty () && !isinf (height) && !equal (iv[LEFT], iv[RIGHT]))
258 bldgs.push_front (Building (iv[LEFT], height, height, iv[RIGHT], max_slope_));
260 internal_build_skyline (&bldgs, &buildings_);
261 assert (is_legal_skyline ());
264 Skyline::Skyline (vector<Offset> const &points, Real max_slope, Direction sky)
267 max_slope_ = max_slope;
269 for (vsize i = 1; i < points.size (); i++)
271 buildings_.push_back (Building (points[i-1][X_AXIS], sky * points[i-1][Y_AXIS],
272 points[i][X_AXIS], sky * points[i][Y_AXIS],
277 assert (is_legal_skyline ());
281 Skyline::merge (Skyline const &other)
283 assert (sky_ == other.sky_);
285 list<Building> other_bld (other.buildings_);
286 list<Building> my_bld;
287 my_bld.splice (my_bld.begin (), buildings_);
288 internal_merge_skyline (&other_bld, &my_bld, &buildings_);
289 assert (is_legal_skyline ());
293 Skyline::insert (Box const &b, Axis a)
295 list<Building> other_bld;
296 list<Building> my_bld;
298 Real height = sky_ * b[other_axis (a)][sky_];
300 my_bld.splice (my_bld.begin (), buildings_);
301 single_skyline (Building (iv[LEFT], height, height, iv[RIGHT], max_slope_), &other_bld, max_slope_);
302 internal_merge_skyline (&other_bld, &my_bld, &buildings_);
303 assert (is_legal_skyline ());
307 Skyline::raise (Real r)
309 list<Building>::iterator end = buildings_.end ();
310 for (list<Building>::iterator i = buildings_.begin (); i != end; i++)
312 i->start_height_ += sky_ * r;
313 i->end_height_ += sky_ * r;
314 i->zero_height_ += sky_ * r;
316 assert (is_legal_skyline ());
320 Skyline::distance (Skyline const &other) const
322 assert (sky_ == -other.sky_);
323 list<Building>::const_iterator i = buildings_.begin ();
324 list<Building>::const_iterator j = other.buildings_.begin ();
326 Real dist = -infinity_f;
327 while (i != buildings_.end () && j != other.buildings_.end ())
329 Interval iv = intersection (i->iv_, j->iv_);
330 dist = max (dist, max (i->height (iv[LEFT]) + j->height (iv[LEFT]),
331 i->height (iv[RIGHT]) + j->height (iv[RIGHT])));
332 if (i->iv_[RIGHT] <= j->iv_[RIGHT])
341 Skyline::height (Real airplane) const
343 assert (!isinf (airplane));
345 list<Building>::const_iterator i;
346 for (i = buildings_.begin (); i != buildings_.end (); i++)
348 if (i->iv_[RIGHT] >= airplane)
349 return sky_ * i->height (airplane);
357 Skyline::max_height () const
360 s.set_minimum_height (0);
361 return sky_ * distance (s);
365 Skyline::set_minimum_height (Real h)
368 s.buildings_.front ().start_height_ = h * sky_;
369 s.buildings_.front ().end_height_ = h * sky_;
370 s.buildings_.front ().zero_height_ = h * sky_;
375 to_stencil (Skyline const &line)
377 vector<Offset> points (line.to_points ());
380 for (vsize i = 1; i < points.size (); i++)
382 if (points[i-1].is_sane () && points[i].is_sane ())
385 = Line_interface::make_line (0.1, points[i-1], points[i]);
386 ret.add_stencil (line);
393 Skyline::to_points () const
398 for (list<Building>::const_iterator i (buildings_.begin ());
399 i != buildings_.end (); i++)
402 out.push_back (Offset ((*i).iv_[LEFT], sky_ * (*i).start_height_));
404 out.push_back (Offset ((*i).iv_[RIGHT], sky_ * (*i).end_height_));