+ build skyline from a set of boxes. If horizon_padding > 0, expand all the boxes
+ by that amount and add 45-degree sloped boxes to the edges of each box (of
+ width horizon_padding). That is, the total amount of horizontal expansion is
+ horizon_padding*4, half of which is sloped and half of which is flat.
+
+ Boxes should have fatness in the horizon_axis (after they are expanded by
+ horizon_padding), otherwise they are ignored.
+ */
+Skyline::Skyline (vector<Box> const &boxes, Real horizon_padding, Axis horizon_axis, Direction sky)
+{
+ list<Box> filtered_boxes;
+ sky_ = sky;
+
+ Axis vert_axis = other_axis (horizon_axis);
+ for (vsize i = 0; i < boxes.size (); i++)
+ {
+ Interval iv = boxes[i][horizon_axis];
+ iv.widen (horizon_padding);
+ if (iv.length () > EPS && !boxes[i][vert_axis].is_empty ())
+ filtered_boxes.push_front (boxes[i]);
+ }
+
+ buildings_ = internal_build_skyline (&filtered_boxes, horizon_padding, horizon_axis, sky);
+}
+
+Skyline::Skyline (Box const &b, Real horizon_padding, Axis horizon_axis, Direction sky)
+{
+ sky_ = sky;
+ Building front (b, horizon_padding, horizon_axis, sky);
+ single_skyline (front, b[horizon_axis][LEFT], horizon_padding, &buildings_);
+}
+
+void
+Skyline::merge (Skyline const &other)
+{
+ assert (sky_ == other.sky_);
+
+ list<Building> other_bld (other.buildings_);
+ list<Building> my_bld;
+ my_bld.splice (my_bld.begin (), buildings_);
+ internal_merge_skyline (&other_bld, &my_bld, &buildings_);
+}
+
+void
+Skyline::insert (Box const &b, Real horizon_padding, Axis a)
+{
+ list<Building> other_bld;
+ list<Building> my_bld;
+
+ if (isnan (b[other_axis (a)][LEFT])
+ || isnan (b[other_axis (a)][RIGHT]))
+ {
+ programming_error ("insane box for skyline");
+ return;
+ }
+
+ /* do the same filtering as in Skyline (vector<Box> const&, etc.) */
+ Interval iv = b[a];
+ iv.widen (horizon_padding);
+ if (iv.length () <= EPS || b[other_axis (a)].is_empty ())
+ return;
+
+ my_bld.splice (my_bld.begin (), buildings_);
+ single_skyline (Building (b, horizon_padding, a, sky_), b[a][LEFT], horizon_padding, &other_bld);
+ internal_merge_skyline (&other_bld, &my_bld, &buildings_);
+}
+
+void
+Skyline::raise (Real r)
+{
+ list<Building>::iterator end = buildings_.end ();
+ for (list<Building>::iterator i = buildings_.begin (); i != end; i++)
+ i->y_intercept_ += sky_ * r;
+}
+
+void
+Skyline::shift (Real s)
+{
+ list<Building>::iterator end = buildings_.end ();
+ for (list<Building>::iterator i = buildings_.begin (); i != end; i++)
+ {
+ i->end_ += s;
+ i->y_intercept_ -= s * i->slope_;
+ }
+}