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
-
static void
print_buildings (list<Building> const &b)
{
{
bool last_empty = false;
list<Building>::iterator i;
+
for (i = buildings_.begin (); i != buildings_.end (); i++)
{
if (last_empty && i->y_intercept_ == -infinity_f)
break;
}
- /* only include buildings wider than epsilon */
- if (end > x + EPS)
+ if (end >= x)
{
b.leading_part (end);
b.start_ = last_end;
static void
single_skyline (Building b, list<Building> *const ret)
{
- if (b.end_ > b.start_ + EPS)
- {
- ret->push_back (Building (-infinity_f, -infinity_f,
- -infinity_f, b.start_));
- ret->push_back (b);
- 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
continue;
}
- if (x1 > last_end + EPS)
+ if (x1 >= last_end)
result.push_back (Building (last_end, -infinity_f, -infinity_f, x1));
result.push_back (*i);
/*
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<Box> const &boxes, Axis horizon_axis, Direction sky)
{
list<Building> 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 ();
/*
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<Drul_array<Offset> > const &segments, Axis horizon_axis, Direction sky)
{
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));
}
sky_ = sky;
Building front (b, horizon_axis, sky);
single_skyline (front, &buildings_);
+ normalize ();
}
void
}
/* do the same filtering as in Skyline (vector<Box> 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_);
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<Building> pad_buildings;
for (list<Building>::const_iterator i = buildings_.begin (); i != buildings_.end (); ++i)
{
return sky_ * ret;
}
+Direction
+Skyline::direction () const
+{
+ return sky_;
+}
+
Real
Skyline::left () const
{
Real x = robust_scm2double (x_scm, 0.0);
return scm_from_double (Skyline::unsmob (skyline_scm)->height (x));
}
+
+LY_DEFINE (ly_skyline_empty_p, "ly:skyline-empty?",
+ 1, 0, 0, (SCM sky),
+ "Return whether @var{sky} is empty.")
+{
+ Skyline *s = Skyline::unsmob (sky);
+ LY_ASSERT_SMOB (Skyline, sky, 1);
+ return scm_from_bool (s->is_empty ());
+}