/*
This file is part of LilyPond, the GNU music typesetter.
- Copyright (C) 1997--2011 Han-Wen Nienhuys <hanwen@xs4all.nl>
+ Copyright (C) 1997--2012 Han-Wen Nienhuys <hanwen@xs4all.nl>
LilyPond is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
merge_possible = false;
/*
- this case (distant half collide),
-
- |
- x |
- | x
- |
-
- the noteheads may be closer than this case (close half collide)
-
- |
- |
- x
- x
- |
- |
-
- */
+ * this case (distant half collide),
+ *
+ * |
+ * x |
+ * | x
+ * |
+ *
+ * the noteheads may be closer than this case (close half collide)
+ *
+ * |
+ * |
+ * x
+ * x
+ * |
+ * |
+ *
+ */
/* TODO: filter out the 'o's in this configuration, since they're no
- part in the collision.
-
- |
- x|o
- x|o
- x
-
- */
+ * part in the collision.
+ *
+ * |
+ * x|o
+ * x|o
+ * x
+ *
+ */
bool close_half_collide = false;
bool distant_half_collide = false;
full_collide = full_collide || (close_half_collide
&& distant_half_collide);
- Real shift_amount = 1;
-
- bool touch = (ups[0] >= dps.back ());
- /* As a special case, if the topmost part of the downstem chord is a second,
- the top note of which is the same pitch as the lowest upstem note, they
- shouldn't count as touching.
+ /* If the only collision is in the extreme noteheads,
+ then their stems can line up and the chords just 'touch'.
+ A half collision with the next note along the chord prevents touching.
*/
- if (dps.back () == ups[0] && dps.size () > 1 && dps[dps.size () - 2] == ups[0] - 1)
- touch = false;
-
- if (touch)
- shift_amount *= -1;
-
- /* For full collisions, the right hand head may obscure dots, so
- make sure the dotted heads go to the right. */
+ bool touch = false;
+ if (ups[0] >= dps.back ()
+ && (dps.size () < 2 || ups[0] >= dps[dps.size () - 2] + 2)
+ && (ups.size () < 2 || ups[1] >= dps.back () + 2))
+ touch = true;
+
+ /* Determine which chord goes on the left, and which goes right.
+ Up-stem usually goes on the right, but if chords just 'touch' we can put
+ both stems on a common vertical line. In the presense of collisions,
+ right hand heads may obscure dots, so dotted heads to go the right.
+ */
+ Real shift_amount = 1;
bool stem_to_stem = false;
- if (full_collide)
+ if ((full_collide
+ || ((close_half_collide || distant_half_collide)
+ && to_boolean (me->get_property ("prefer-dotted-right"))))
+ && Rhythmic_head::dot_count (head_up) < Rhythmic_head::dot_count (head_down))
{
- if (Rhythmic_head::dot_count (head_up) > Rhythmic_head::dot_count (head_down))
- shift_amount = 1;
- else if (Rhythmic_head::dot_count (head_up) < Rhythmic_head::dot_count (head_down))
+ shift_amount = -1;
+ if (!touch)
+ // remember to leave clearance between stems
stem_to_stem = true;
}
+ else if (touch)
+ {
+ // Up-stem note on a line has a raised dot, so no risk of collision
+ Grob *staff = Staff_symbol_referencer::get_staff_symbol (me);
+ if ((full_collide
+ || (!Staff_symbol_referencer::on_line (staff, ups[0])
+ && to_boolean (me->get_property ("prefer-dotted-right"))))
+ && Rhythmic_head::dot_count (head_up) > Rhythmic_head::dot_count (head_down))
+ touch = false;
+ else
+ shift_amount = -1;
+ }
/* The solfa is a triangle, which is inverted depending on stem
direction. In case of a collision, one of them should be removed,
&& (up_style == ly_symbol2scm ("fa") || up_style == ly_symbol2scm ("faThin"))
&& (down_style == ly_symbol2scm ("fa") || down_style == ly_symbol2scm ("faThin")))
{
- Interval uphead_size = head_up->extent (head_up, Y_AXIS);
Offset att = Offset (0.0, -1.0);
head_up->set_property ("stem-attachment", ly_offset2scm (att));
head_up->set_property ("transparent", SCM_BOOL_T);
/* TODO: these numbers are magic; should devise a set of grob props
to tune this behavior. */
else if (stem_to_stem)
- shift_amount = -abs (shift_amount) * 0.65;
- else if (close_half_collide && !touch)
+ shift_amount *= 0.65;
+ else if (touch)
+ shift_amount *= 0.5;
+ else if (close_half_collide)
shift_amount *= 0.52;
- else if (distant_half_collide && !touch)
- shift_amount *= 0.4;
- else if (distant_half_collide || close_half_collide || full_collide)
+ else if (full_collide)
shift_amount *= 0.5;
+ else if (distant_half_collide)
+ shift_amount *= 0.4;
/* we're meshing. */
else if (Rhythmic_head::dot_count (head_up) || Rhythmic_head::dot_count (head_down))
shift_amount *= 0.75;
}
- /*
- * Fix issue #44:
- *
- * Dots from left note head collide with right note head. Only occurs
- * with a close half collide, if the left note head is between
- * lines and the right note head is on a line, and if right note head
- * hasn't got any dots.
+ /* If any dotted notes ended up on the left,
+ tell the Dot_Columnn to avoid the note heads on the right.
*/
- if (close_half_collide
- && Rhythmic_head::dot_count (head_up)
- && !Rhythmic_head::dot_count (head_down))
+ if (shift_amount < -1e-6
+ && Rhythmic_head::dot_count (head_up))
{
- Grob *staff = Staff_symbol_referencer::get_staff_symbol (me);
- if (!Staff_symbol_referencer::on_line (staff, ups[0]))
- {
- /*
- TODO: consider junking the else body.
- */
- if (to_boolean (me->get_property ("prefer-dotted-right")))
- shift_amount = 0.5;
- else
- {
- Grob *d = unsmob_grob (head_up->get_object ("dot"));
- Grob *parent = d->get_parent (X_AXIS);
- if (Dot_column::has_interface (parent))
- Side_position_interface::add_support (parent, head_down);
- }
- }
+ Grob *d = unsmob_grob (head_up->get_object ("dot"));
+ Grob *parent = d->get_parent (X_AXIS);
+ if (Dot_column::has_interface (parent))
+ Side_position_interface::add_support (parent, head_down);
}
-
- /* For full or close half collisions, the right hand head may
- obscure dots. Move dots to the right. */
- if (abs (shift_amount) > 1e-6
- && Rhythmic_head::dot_count (head_down) > Rhythmic_head::dot_count (head_up)
- && (full_collide || close_half_collide))
+ else if (Rhythmic_head::dot_count (head_down))
{
Grob *d = unsmob_grob (head_down->get_object ("dot"));
Grob *parent = d->get_parent (X_AXIS);
-
- /*
- FIXME:
-
- |
- x . o
- |
-
-
- the . is put right of o which is erroneous o force-shifted
- far to the right.
- */
if (Dot_column::has_interface (parent))
{
Grob *stem = unsmob_grob (head_up->get_object ("stem"));
+ // Loop over all heads on an up-pointing-stem to see if dots
+ // need to clear any heads suspended on its right side.
extract_grob_set (stem, "note-heads", heads);
for (vsize i = 0; i < heads.size (); i++)
Side_position_interface::add_support (parent, heads[i]);
}
}
+ // In meshed chords with dots on the left, adjust dot direction
+ if (shift_amount > 1e-6
+ && Rhythmic_head::dot_count (head_down))
+ {
+ Grob *dot_down = unsmob_grob (head_down->get_object ("dot"));
+ Grob *col_down = dot_down->get_parent (X_AXIS);
+ Direction dir = UP;
+ if (Rhythmic_head::dot_count (head_up))
+ {
+ Grob *dot_up = unsmob_grob (head_up->get_object ("dot"));
+ Grob *col_up = dot_up->get_parent (X_AXIS);
+ if (col_up == col_down) // let the common DotColumn arrange dots
+ dir = CENTER;
+ else // conform to the dot direction on the up-stem chord
+ dir = robust_scm2dir (dot_up->get_property ("direction"), UP);
+ }
+ if (dir != CENTER)
+ {
+ Grob *stem = unsmob_grob (head_down->get_object ("stem"));
+ extract_grob_set (stem, "note-heads", heads);
+ for (vsize i = 0; i < heads.size (); i++)
+ unsmob_grob (heads[i]->get_object ("dot"))
+ ->set_property ("direction", scm_from_int (dir));
+ }
+ }
+
Direction d = UP;
do
{