- for (vsize i = 1; i < clash_groups[d].size (); i++)
- {
- Slice prev = extents[d][i - 1];
- prev.intersect (extents[d][i]);
- if (prev.length () > 0
- || (extents[-d].size () && d * (extents[d][i][-d] - extents[-d][0][d]) < 0))
- for (vsize j = i; j < clash_groups[d].size (); j++)
- offsets[d][j] += d * 0.5;
- }
+ Real offset = inner_offset;
+ vector<int> shifts;
+ for (vsize i = 0; i < clash_groups[d].size (); i++)
+ {
+ Grob *col = clash_groups[d][i];
+ SCM sh = col->get_property ("horizontal-shift");
+ shifts.push_back (robust_scm2int (sh, 0));
+
+ if (i == 0)
+ offset = inner_offset;
+ else if (shifts[i] == shifts[i - 1])
+ {
+ // Match the previous notecolumn offset,
+ // but warn if the user did not set these equal shifts explictly
+ if (!scm_is_number (sh))
+ col->warning (_ ("ignoring too many clashing note columns"));
+ }
+ else if (extents[d][i][UP] > extents[d][i - 1][DOWN]
+ && extents[d][i][DOWN] < extents[d][i - 1][UP])
+ offset += 1.0; // fully clear the inner-voice heads
+ else
+ {
+ // check if we cross the inner voice
+ if (d * extents[d][i][-d] >= d * extents[d][i - 1][d])
+ offset += Stem::is_valid_stem (stems[d][i - 1])
+ ? 1.0 : 0.5;
+ else if (Stem::is_valid_stem (stems[d][i]))
+ offset += 0.5;
+ // check if we cross the opposite-stemmed voices
+ if (d * extents[d][i][-d] < d * extent_union[-d][d])
+ offset = max (offset, 0.5);
+ if (extents[-d].size ()
+ && extents[d][i][UP] > extents[-d][0][DOWN]
+ && extents[d][i][DOWN] < extents[-d][0][UP])
+ offset = max (offset, 1.0);
+ }
+ offsets[d].push_back (d * offset);
+ }