getHorizontalOffset method
Get horizontal offset for this voice, in pixels.
Uses horizontalOffset (expressed in staff spaces) when set.
Otherwise the offset follows the stem direction of the voice, per Gould, Behind Bars: when noteheads of opposing voices collide, the stem-down voice is displaced to the right of the stem-up voice so the noteheads stay legible. The offset therefore pairs with getStemDirection:
| Voice | Stems | Offset |
|---|---|---|
| 1 | up | none |
| 2 | down | 0.6 staff spaces |
| 3 | up | none |
| 4 | down | 0.6 staff spaces |
Limitation: this is a static, per-voice rule. Real engraving only displaces a notehead when the voices actually collide (unison or an interval of a second at the same rhythmic position), and it keeps the column aligned everywhere else. Voices beyond 4 reuse the same odd/even rule; they are rare and usually need manual horizontalOffset.
Implementation
double getHorizontalOffset(double staffSpace) {
if (horizontalOffset != null) {
return horizontalOffset! * staffSpace;
}
// Stem-up voices (odd) keep the reference column; stem-down voices (even)
// move right by one notehead width minus the stem, ~0.6 staff spaces.
return number.isEven ? staffSpace * 0.6 : 0.0;
}