/*
This file is part of LilyPond, the GNU music typesetter.
- Copyright (C) 2006--2011 Joe Neeman <joeneeman@gmail.com>
+ Copyright (C) 2006--2012 Joe Neeman <joeneeman@gmail.com>
LilyPond is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
vector<Offset> ps (to_points (X_AXIS));
for (vsize i = 0; i < ps.size (); i++)
- printf ("(%f,%f)%s" , ps[i][X_AXIS], ps[i][Y_AXIS],
- (i%2)==1 ? "\n" : " ");
+ printf ("(%f,%f)%s", ps[i][X_AXIS], ps[i][Y_AXIS],
+ (i % 2) == 1 ? "\n" : " ");
}
Building::Building (Real start, Real start_height, Real end_height, Real end)
Real
Building::height (Real x) const
{
- return isinf (x) ? y_intercept_ : slope_*x + y_intercept_;
+ return isinf (x) ? y_intercept_ : slope_ * x + y_intercept_;
}
void
{
Building c = s->front ();
if (c.conceals (b, start_x))
- return start_x;
+ return start_x;
Real i = b.intersection_x (c);
if (i > start_x && i <= b.end_ && i <= c.end_)
- return i;
+ return i;
start_x = c.end_;
if (b.end_ > c.end_)
- s->pop_front ();
+ s->pop_front ();
}
return b.end_;
}
/* their slopes were not equal, so there is an intersection point */
Real i = intersection_x (other);
return (i <= x && slope_ > other.slope_)
- || (i > x && slope_ < other.slope_);
+ || (i > x && slope_ < other.slope_);
}
void
Skyline::internal_merge_skyline (list<Building> *s1, list<Building> *s2,
- list<Building> *const result)
+ list<Building> *const result)
{
if (s1->empty () || s2->empty ())
{
while (!s1->empty ())
{
if (s2->front ().conceals (s1->front (), x))
- swap (s1, s2);
+ swap (s1, s2);
Building b = s1->front ();
Real end = first_intersection (b, s2, x);
if (s2->empty ())
- {
- result->push_front (b);
- break;
- }
+ {
+ result->push_front (b);
+ break;
+ }
/* only include buildings wider than epsilon */
if (end > x + EPS)
- {
- b.leading_part (end);
- result->push_front (b);
- }
+ {
+ b.leading_part (end);
+ result->push_front (b);
+ }
if (end >= s1->front ().end_)
- s1->pop_front ();
+ s1->pop_front ();
x = end;
}
bool sloped_neighbours = horizon_padding > 0 && !isinf (start) && !isinf (b.end_);
if (!isinf (b.end_))
ret->push_front (Building (b.end_ + horizon_padding, -infinity_f,
- -infinity_f, infinity_f));
+ -infinity_f, infinity_f));
if (sloped_neighbours)
ret->push_front (b.sloped_neighbour (start, horizon_padding, RIGHT));
if (!isinf (start))
ret->push_front (Building (-infinity_f, -infinity_f,
- -infinity_f, start - horizon_padding));
+ -infinity_f, start - horizon_padding));
}
/* remove a non-overlapping set of boxes from BOXES and build a skyline
Interval iv = (*i)[horizon_axis];
if (iv[LEFT] - horizon_padding < last_end)
- {
- i++;
- continue;
- }
+ {
+ i++;
+ continue;
+ }
if (iv[LEFT] - horizon_padding > last_end + EPS)
- result.push_front (Building (last_end, -infinity_f, -infinity_f, iv[LEFT] - 2*horizon_padding));
+ result.push_front (Building (last_end, -infinity_f, -infinity_f, iv[LEFT] - 2 * horizon_padding));
Building b (*i, horizon_padding, horizon_axis, sky);
bool sloped_neighbours = horizon_padding > 0 && !isinf (iv.length ());
if (sloped_neighbours)
- result.push_front (b.sloped_neighbour (iv[LEFT] - horizon_padding, horizon_padding, LEFT));
+ result.push_front (b.sloped_neighbour (iv[LEFT] - horizon_padding, horizon_padding, LEFT));
result.push_front (b);
if (sloped_neighbours)
- result.push_front (b.sloped_neighbour (iv[LEFT] - horizon_padding, horizon_padding, RIGHT));
+ result.push_front (b.sloped_neighbour (iv[LEFT] - horizon_padding, horizon_padding, RIGHT));
list<Box>::iterator j = i++;
boxes->erase (j);
a_ = a;
}
- bool operator() (Box const &b1, Box const &b2)
+ bool operator () (Box const &b1, Box const &b2)
{
return b1[a_][LEFT] < b2[a_][LEFT];
}
{
list<Building> result;
single_skyline (Building (boxes->front (), horizon_padding, horizon_axis, sky),
- boxes->front ()[horizon_axis][LEFT] - horizon_padding,
- horizon_padding, &result);
+ boxes->front ()[horizon_axis][LEFT] - horizon_padding,
+ horizon_padding, &result);
return result;
}
list<Building> one = partials.front ();
partials.pop_front ();
if (partials.empty ())
- return one;
+ return one;
list<Building> two = partials.front ();
partials.pop_front ();
added to it.
*/
-Skyline::Skyline (Skyline const &src, Real horizon_padding, Axis a)
+Skyline::Skyline (Skyline const &src, Real horizon_padding, Axis /*a*/)
{
/*
We extract boxes from the skyline, then build a new skyline from
list<Box> boxes;
// establish a baseline box
+ // FIXME: This has hardcoded logic, assuming a == X_AXIS!
boxes.push_back (Box (Interval (-infinity_f, infinity_f),
- Interval (0, 0)));
+ Interval (0, 0)));
list<Building>::const_iterator end = src.buildings_.end ();
- for (list<Building>::const_iterator i = src.buildings_.begin (); i != end; start=i->end_, i++ )
+ for (list<Building>::const_iterator i = src.buildings_.begin (); i != end; start = i->end_, i++)
if ((i->slope_ == 0) && !isinf (i->y_intercept_))
boxes.push_back (Box (Interval (start, i->end_),
- Interval (-infinity_f , i->y_intercept_)));
+ Interval (-infinity_f, i->y_intercept_)));
buildings_ = internal_build_skyline (&boxes, horizon_padding, X_AXIS, UP);
sky_ = src.sky_;
}
-
/*
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
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]);
+ filtered_boxes.push_front (boxes[i]);
}
buildings_ = internal_build_skyline (&filtered_boxes, horizon_padding, horizon_axis, sky);
sky_ = sky;
Building front (b, horizon_padding, horizon_axis, sky);
single_skyline (front, b[horizon_axis][LEFT] - horizon_padding,
- horizon_padding, &buildings_);
+ horizon_padding, &buildings_);
}
void
my_bld.splice (my_bld.begin (), buildings_);
single_skyline (Building (b, horizon_padding, a, sky_), b[a][LEFT] - horizon_padding,
- horizon_padding, &other_bld);
+ horizon_padding, &other_bld);
internal_merge_skyline (&other_bld, &my_bld, &buildings_);
}
Real
Skyline::distance (Skyline const &other, Real horizon_padding) const
+{
+ Real dummy;
+ return internal_distance (other, horizon_padding, &dummy);
+}
+
+Real
+Skyline::touching_point (Skyline const &other, Real horizon_padding) const
+{
+ Real touch;
+ internal_distance (other, horizon_padding, &touch);
+ return touch;
+}
+
+Real
+Skyline::internal_distance (Skyline const &other, Real horizon_padding, Real *touch_point) const
{
assert (sky_ == -other.sky_);
Skyline const *padded_this = this;
Skyline const *padded_other = &other;
+ bool created_tmp_skylines = false;
/*
For systems, padding is not added at creation time. Padding is
{
padded_this = new Skyline (*padded_this, horizon_padding, X_AXIS);
padded_other = new Skyline (*padded_other, horizon_padding, X_AXIS);
+ created_tmp_skylines = true;
}
list<Building>::const_iterator i = padded_this->buildings_.begin ();
Real dist = -infinity_f;
Real start = -infinity_f;
+ Real touch = -infinity_f;
while (i != padded_this->buildings_.end () && j != padded_other->buildings_.end ())
{
Real end = min (i->end_, j->end_);
Real start_dist = i->height (start) + j->height (start);
Real end_dist = i->height (end) + j->height (end);
dist = max (dist, max (start_dist, end_dist));
+
+ if (end_dist == dist)
+ touch = end;
+ else if (start_dist == dist)
+ touch = start;
+
if (i->end_ <= j->end_)
- i++;
+ i++;
else
- j++;
+ j++;
start = end;
}
+
+ if (created_tmp_skylines)
+ {
+ delete padded_this;
+ delete padded_other;
+ }
+
+ *touch_point = touch;
return dist;
}
for (i = buildings_.begin (); i != buildings_.end (); i++)
{
if (i->end_ >= airplane)
- return sky_ * i->height (airplane);
+ return sky_ * i->height (airplane);
}
assert (0);
return sky_ * distance (s);
}
+Real
+Skyline::max_height_position () const
+{
+ Skyline s (-sky_);
+ s.set_minimum_height (0);
+ return touching_point (s);
+}
+
void
Skyline::set_minimum_height (Real h)
{
merge (s);
}
-
vector<Offset>
Skyline::to_points (Axis horizon_axis) const
{
/****************************************************************/
-
IMPLEMENT_SIMPLE_SMOBS (Skyline);
IMPLEMENT_TYPE_P (Skyline, "ly:skyline?");
IMPLEMENT_DEFAULT_EQUAL_P (Skyline);
SCM
-Skyline::mark_smob (SCM)
+Skyline::mark_smob (SCM s)
{
- ASSERT_LIVE_IS_ALLOWED ();
+ ASSERT_LIVE_IS_ALLOWED (s);
return SCM_EOL;
}
return 1;
}
+
+MAKE_SCHEME_CALLBACK_WITH_OPTARGS (Skyline, get_touching_point, 3, 1, "")
+SCM
+Skyline::get_touching_point (SCM skyline_scm, SCM other_skyline_scm, SCM horizon_padding_scm)
+{
+ LY_ASSERT_SMOB (Skyline, other_skyline_scm, 1);
+
+ Real horizon_padding = 0;
+ if (horizon_padding_scm != SCM_UNDEFINED)
+ {
+ LY_ASSERT_TYPE (scm_is_number, horizon_padding_scm, 3);
+ horizon_padding = scm_to_double (horizon_padding_scm);
+ }
+
+ Skyline *skyline = Skyline::unsmob (skyline_scm);
+ Skyline *other_skyline = Skyline::unsmob (other_skyline_scm);
+ return scm_from_double (skyline->touching_point (*other_skyline, horizon_padding));
+}
+
+MAKE_SCHEME_CALLBACK_WITH_OPTARGS (Skyline, get_distance, 3, 1, "")
+SCM
+Skyline::get_distance (SCM skyline_scm, SCM other_skyline_scm, SCM horizon_padding_scm)
+{
+ LY_ASSERT_SMOB (Skyline, other_skyline_scm, 1);
+
+ Real horizon_padding = 0;
+ if (horizon_padding_scm != SCM_UNDEFINED)
+ {
+ LY_ASSERT_TYPE (scm_is_number, horizon_padding_scm, 3);
+ horizon_padding = scm_to_double (horizon_padding_scm);
+ }
+
+ Skyline *skyline = Skyline::unsmob (skyline_scm);
+ Skyline *other_skyline = Skyline::unsmob (other_skyline_scm);
+ return scm_from_double (skyline->distance (*other_skyline, horizon_padding));
+}
+
+MAKE_SCHEME_CALLBACK (Skyline, get_max_height, 1)
+SCM
+Skyline::get_max_height (SCM skyline_scm)
+{
+ return scm_from_double (Skyline::unsmob (skyline_scm)->max_height ());
+}
+
+MAKE_SCHEME_CALLBACK (Skyline, get_max_height_position, 1)
+SCM
+Skyline::get_max_height_position (SCM skyline_scm)
+{
+ return scm_from_double (Skyline::unsmob (skyline_scm)->max_height_position ());
+}
+
+MAKE_SCHEME_CALLBACK (Skyline, get_height, 2)
+SCM
+Skyline::get_height (SCM skyline_scm, SCM x_scm)
+{
+ Real x = robust_scm2double (x_scm, 0.0);
+ return scm_from_double (Skyline::unsmob (skyline_scm)->height (x));
+}