X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=lily%2Fskyline.cc;h=31f4c5a1841a9547f2f196dcae2abe17f2132594;hb=ecc41fd08c437396edb27d1fb82c977e7404803e;hp=bf95fe35418153ce65237a415a29c4d4553ecde0;hpb=0d1e65a22f4689d6f497243cf65df1a8d3fc8561;p=lilypond.git diff --git a/lily/skyline.cc b/lily/skyline.cc index bf95fe3541..31f4c5a184 100644 --- a/lily/skyline.cc +++ b/lily/skyline.cc @@ -54,11 +54,18 @@ a DOWN skyline with an UP skyline, we need to flip the DOWN skyline first. This means that the merging routine doesn't need to be aware of direction, but the distance routine does. -*/ -/* If we start including very thin buildings, numerical accuracy errors can - arise. Therefore, we ignore all buildings that are less than epsilon wide. */ -#define EPS 1e-5 + From 2007 through 2012, buildings of width less than EPS were discarded, + citing numerical accuracy concerns. We remember that floating point + comparisons of nearly-equal values can be affected by rounding error. + Also, some target machines use the x87 floating point unit, which provides + extended precision for intermediate results held in registers. On this type + of hardware comparisons such as + double c = 1.0/3.0; boolean compare = (c == 1.0/3.0) + could go either way because the 1.0/3.0 is allowed to be kept + higher precision than the variable 'c'. + Alert to these considerations, we now accept buildings of zero-width. +*/ static void print_buildings (list const &b) @@ -301,8 +308,7 @@ Skyline::internal_merge_skyline (list *s1, list *s2, break; } - /* only include buildings wider than epsilon */ - if (end > x + EPS) + if (end >= x) { b.leading_part (end); b.start_ = last_end; @@ -329,20 +335,15 @@ empty_skyline (list *const ret) static void single_skyline (Building b, list *const ret) { - if (b.end_ > b.start_ + EPS) - { - if (b.start_ != -infinity_f) - ret->push_back (Building (-infinity_f, -infinity_f, - -infinity_f, b.start_)); - ret->push_back (b); - if (b.end_ != infinity_f) - ret->push_back (Building (b.end_, -infinity_f, - -infinity_f, infinity_f)); - } - else - { - empty_skyline (ret); - } + assert (b.end_ >= b.start_); + + if (b.start_ != -infinity_f) + ret->push_back (Building (-infinity_f, -infinity_f, + -infinity_f, b.start_)); + ret->push_back (b); + if (b.end_ != infinity_f) + ret->push_back (Building (b.end_, -infinity_f, + -infinity_f, infinity_f)); } /* remove a non-overlapping set of boxes from BOXES and build a skyline @@ -377,7 +378,8 @@ non_overlapping_skyline (list *const buildings) continue; } - if (x1 > last_end + EPS) + // Insert empty Buildings into any gaps. (TODO: is this needed? -KOH) + if (x1 > last_end) result.push_back (Building (last_end, -infinity_f, -infinity_f, x1)); result.push_back (*i); @@ -476,20 +478,16 @@ Skyline::Skyline (Direction sky) /* Build skyline from a set of boxes. - Boxes should have fatness in the horizon_axis, otherwise they are ignored. + Boxes should be non-empty on both axes. Otherwise, they will be ignored */ Skyline::Skyline (vector const &boxes, Axis horizon_axis, Direction sky) { list buildings; sky_ = sky; - Axis vert_axis = other_axis (horizon_axis); for (vsize i = 0; i < boxes.size (); i++) - { - Interval iv = boxes[i][horizon_axis]; - if (iv.length () > EPS && !boxes[i][vert_axis].is_empty ()) - buildings.push_front (Building (boxes[i], horizon_axis, sky)); - } + if (!boxes[i].is_empty ()) + buildings.push_front (Building (boxes[i], horizon_axis, sky)); buildings_ = internal_build_skyline (&buildings); normalize (); @@ -498,7 +496,8 @@ Skyline::Skyline (vector const &boxes, Axis horizon_axis, Direction sky) /* build skyline from a set of line segments. - Buildings should have fatness in the horizon_axis, otherwise they are ignored. + Segments can be articulated from left to right or right to left. + In the case of the latter, they will be stored internally as left to right. */ Skyline::Skyline (vector > const &segments, Axis horizon_axis, Direction sky) { @@ -518,7 +517,7 @@ Skyline::Skyline (vector > const &segments, Axis horizon_axis Real y1 = left[other_axis (horizon_axis)] * sky; Real y2 = right[other_axis (horizon_axis)] * sky; - if (x1 + EPS < x2) + if (x1 <= x2) buildings.push_back (Building (x1, y1, y2, x2)); } @@ -594,8 +593,7 @@ Skyline::insert (Box const &b, Axis a) } /* do the same filtering as in Skyline (vector const&, etc.) */ - Interval iv = b[a]; - if (iv.length () <= EPS || b[other_axis (a)].is_empty ()) + if (b.is_empty ()) return; my_bld.splice (my_bld.begin (), buildings_); @@ -654,6 +652,12 @@ Skyline::internal_distance (Skyline const &other, Real horizon_padding, Real *to Skyline Skyline::padded (Real horizon_padding) const { + if (horizon_padding < 0.0) + warning ("Cannot have negative horizon padding. Junking."); + + if (horizon_padding <= 0.0) + return *this; + list pad_buildings; for (list::const_iterator i = buildings_.begin (); i != buildings_.end (); ++i) {