source file of the GNU LilyPond music typesetter
- (c) 1996--2006 Han-Wen Nienhuys <hanwen@xs4all.nl>
+ (c) 1996--2008 Han-Wen Nienhuys <hanwen@xs4all.nl>
*/
-#include "spanner.hh"
-
-
#include "pointer-group-interface.hh"
#include "libc-extension.hh"
#include "paper-column.hh"
#include "stencil.hh"
#include "system.hh"
#include "warn.hh"
+#include "moment.hh"
Grob *
-Spanner::clone (int count) const
+Spanner::clone () const
{
- return new Spanner (*this, count);
+ return new Spanner (*this);
}
void
if (!left || !right)
return;
- /*
- Check if our parent in X-direction spans equally wide
- or wider than we do.
- */
- for (int a = X_AXIS; a < NO_AXES; a++)
- {
- if (Spanner *parent = dynamic_cast<Spanner *> (get_parent ((Axis)a)))
- {
- if (!parent->spanned_rank_iv ().superset (this->spanned_rank_iv ()))
- {
- programming_error (to_string ("Spanner `%s' is not fully contained in parent spanner `%s'.",
- name ().c_str (),
- parent->name ().c_str ()));
- }
- }
- }
if (get_system () || is_broken ())
return;
programming_error ("no broken bound");
else if (bound->get_system ())
{
- Spanner *span = dynamic_cast<Spanner *> (clone (broken_intos_.size ()));
+ Spanner *span = dynamic_cast<Spanner *> (clone ());
span->set_bound (LEFT, bound);
span->set_bound (RIGHT, bound);
break_points.insert (break_points.begin () + 0, left);
break_points.push_back (right);
+ Slice parent_rank_slice;
+ parent_rank_slice.set_full ();
+
+ /*
+ Check if our parent in X-direction spans equally wide
+ or wider than we do.
+ */
+ for (int a = X_AXIS; a < NO_AXES; a++)
+ {
+ if (Spanner *parent = dynamic_cast<Spanner *> (get_parent ((Axis)a)))
+ {
+ parent_rank_slice.intersect (parent->spanned_rank_interval ());
+ }
+ }
+
for (vsize i = 1; i < break_points.size (); i++)
{
Drul_array<Item *> bounds;
continue;
}
- Spanner *span = dynamic_cast<Spanner *> (clone (broken_intos_.size ()));
+ bool ok = parent_rank_slice.contains (bounds[LEFT]->get_column ()->get_rank ());
+ ok = ok && parent_rank_slice.contains (bounds[RIGHT]->get_column ()->get_rank ());
+
+ if (!ok)
+ {
+ programming_error (to_string ("Spanner `%s' is not fully contained in parent spanner. Ignoring orphaned part",
+ name ().c_str ()));
+ continue;
+ }
+
+
+ Spanner *span = dynamic_cast<Spanner *> (clone ());
span->set_bound (LEFT, bounds[LEFT]);
span->set_bound (RIGHT, bounds[RIGHT]);
}
}
}
- vector_sort (broken_intos_, Spanner::compare);
+ vector_sort (broken_intos_, Spanner::less);
for (vsize i = broken_intos_.size (); i--;)
broken_intos_[i]->break_index_ = i;
}
}
Interval_t<int>
-Spanner::spanned_rank_iv ()
+Spanner::spanned_rank_interval () const
{
Interval_t<int> iv (0, 0);
return iv;
}
+Interval_t<Moment>
+Spanner::spanned_time () const
+{
+ return spanned_time_interval (spanned_drul_[LEFT],
+ spanned_drul_[RIGHT]);
+}
+
+
Item *
Spanner::get_bound (Direction d) const
{
Item *i = dynamic_cast<Item *> (s);
if (!i)
{
- programming_error ("must have Item for spanner bound");
+ programming_error ("must have Item for spanner bound of " + name());
return;
}
Pointer_group_interface::add_grob (i, ly_symbol2scm ("bounded-by-me"), this);
}
-Spanner::Spanner (SCM s, Object_key const *key)
- : Grob (s, key)
+Spanner::Spanner (SCM s)
+ : Grob (s)
{
break_index_ = 0;
spanned_drul_[LEFT] = 0;
spanned_drul_[RIGHT] = 0;
}
-Spanner::Spanner (Spanner const &s, int count)
- : Grob (s, count)
+Spanner::Spanner (Spanner const &s)
+ : Grob (s)
{
spanned_drul_[LEFT] = spanned_drul_[RIGHT] = 0;
}
Grob *
Spanner::find_broken_piece (System *l) const
{
- vsize idx = binary_search (broken_intos_, (Spanner *)l, Spanner::less_than);
+ vsize idx = binary_search (broken_intos_, (Spanner *)l, Spanner::less);
if (idx != VPOS)
return broken_intos_ [idx];
return 0;
}
+Spanner *
+Spanner::broken_neighbor (Direction d) const
+{
+ if (!original_)
+ return 0;
+
+ vsize k = broken_spanner_index (this);
+ Spanner *orig = dynamic_cast<Spanner*> (original_);
+ int j = int (k) + d;
+ if (j < 0 || vsize (j) >= orig->broken_intos_.size ())
+ return 0;
+
+ return orig->broken_intos_[j];
+}
+
int
Spanner::compare (Spanner *const &p1, Spanner *const &p2)
{
}
bool
-Spanner::less_than (Spanner *const &a, Spanner *const &b)
+Spanner::less (Spanner *const &a, Spanner *const &b)
{
return a->get_system ()->get_rank () < b->get_system ()->get_rank ();
}
Spanner::set_spacing_rods (SCM smob)
{
Grob *me = unsmob_grob (smob);
-
- Rod r;
- Spanner *sp = dynamic_cast<Spanner *> (me);
- r.item_drul_[LEFT] = sp->get_bound (LEFT);
- r.item_drul_[RIGHT] = sp->get_bound (RIGHT);
- r.distance_
- = robust_scm2double (me->get_property ("minimum-length"), 0);
-
- r.add_to_cols ();
+ SCM num_length = me->get_property ("minimum-length");
+ if (scm_is_number (num_length))
+ {
+ Rod r;
+ Spanner *sp = dynamic_cast<Spanner *> (me);
+ System *root = get_root_system (me);
+ Drul_array<Item*> bounds (sp->get_bound (LEFT),
+ sp->get_bound (RIGHT));
+ if (!bounds[LEFT] || !bounds[RIGHT])
+ return SCM_UNSPECIFIED;
+
+ vector<Item*> cols (root->broken_col_range (bounds[LEFT]->get_column (),
+ bounds[RIGHT]->get_column ()));
+
+ if (cols.size ())
+ {
+ Rod r ;
+ r.item_drul_[LEFT] = sp->get_bound (LEFT);
+ r.item_drul_[RIGHT] = cols[0]->find_prebroken_piece (LEFT);
+ r.distance_ = robust_scm2double (num_length, 0);
+ r.add_to_cols ();
+
+ r.item_drul_[LEFT] = cols.back ()->find_prebroken_piece (RIGHT);
+ r.item_drul_[RIGHT] = sp->get_bound (RIGHT);
+ r.add_to_cols ();
+ }
+
+ r.distance_ = robust_scm2double (num_length, 0);
+ r.item_drul_[LEFT] = sp->get_bound (LEFT);
+ r.item_drul_[RIGHT] = sp->get_bound (RIGHT);
+ r.add_to_cols ();
+ }
+
return SCM_UNSPECIFIED;
}
Return I such that SP == SP->ORIGINAL ()->BROKEN_INTOS_[I].
*/
int
-broken_spanner_index (Spanner *sp)
+broken_spanner_index (Spanner const *sp)
{
Spanner *parent = dynamic_cast<Spanner *> (sp->original ());
- return find (parent->broken_intos_, sp) - parent->broken_intos_.begin ();
+ /* ugh: casting */
+ return find (parent->broken_intos_, (Spanner*) sp) - parent->broken_intos_.begin ();
}
Spanner *
return dynamic_cast<Spanner *> (unsmob_grob (s));
}
+MAKE_SCHEME_CALLBACK (Spanner, bounds_width, 1);
+SCM
+Spanner::bounds_width (SCM grob)
+{
+ Spanner *me = unsmob_spanner (grob);
+
+
+ Grob *common = me->get_bound (LEFT)->common_refpoint (me->get_bound (RIGHT), X_AXIS);
+
+ Interval w (me->get_bound (LEFT)->relative_coordinate (common, X_AXIS),
+ me->get_bound (RIGHT)->relative_coordinate (common, X_AXIS));
+
+ w -= me->relative_coordinate (common, X_AXIS);
+
+ return ly_interval2scm (w);
+}
+
ADD_INTERFACE (Spanner,
- "spanner-interface",
- "Some objects are horizontally spanned between objects. For\n"
- "example, slur, beam, tie, etc. These grobs form a subtype called\n"
- "@code{Spanner}. All spanners have two span-points (these must be\n"
- "@code{Item} objects), one on the left and one on the right. The left bound is\n"
- "also the X-reference point of the spanner.\n",
- "minimum-length");
+ "Some objects are horizontally spanned between objects. For"
+ " example, slurs, beams, ties, etc. These grobs form a subtype"
+ " called @code{Spanner}. All spanners have two span points"
+ " (these must be @code{Item} objects), one on the left and one"
+ " on the right. The left bound is also the X@tie{}reference"
+ " point of the spanner.",
+
+ /* properties */
+ "minimum-length "
+ "to-barline "
+ );
+