5.4 Offsets and alignments

LilyPond needs to know where each and every grob should be placed. This placement information is stored using relative coordinates: the position of a grob is defined relative to the position of its parent (if we had to use absolute coordinates instead – e.g., distances from the edges of the page – it would be hard to maintain spatial relationships between grobs).

Every grob knows which grob is its parent in the respective axis. For example, a Flag grob knows that its x-parent is a particular Stem grob.

Relative coordinates that describe a grob’s placement are stored in grob properties called X-offset and Y-offset. They are measured in staff spaces. X-offset is the horizontal displacement between a grob’s reference point and the reference point of a grob’s x-parent (similarly with Y-offset).

What is a reference point? It’s a special point that defines the grob’s position. Think about geometry: if you have to define where a figure is placed on a plane, you’ll usually say something like “the lower left corner of this square has coordinates (0, 2)”, or “the center of this circle is at (-1, 3)”. ‘Lower left corner’ and ‘center’ would be the reference points for square and circle, respectively.

This illustration shows where reference points of particular grobs are located, indicated as red dots (for example, the middle staff line for bars and stems, the intersection between the baseline and the left edge for a text box, or the vertical center at the left side for a note head).

{
  \override NoteHead.style = #'altdefault     % for breve

  \time 4/2 g'2-> c''\fermata as'1^"Yogi" |
  b'\breve _"Larry" |
  \mark "Twinkle" e''8 s4.. \bar "|."
}

[image of music]

By overriding the X-offset or Y-offset value we can move grobs relative to their parents:

{
  \override Script.X-offset = 3               % fermata, accent
  \override TextScript.X-offset = 2           % "Yogi", "Larry"
  \override Stem.X-offset = -2
  \override Score.RehearsalMark.Y-offset = 5  % "Twinkle"

  \override NoteHead.style = #'altdefault     % for breve

  \time 4/2 g'2-> c''\fermata as'1^"Yogi" |
  b'\breve _"Larry" |
  \mark "Twinkle" e''8 s4.. \bar "|."
}

[image of music]

Note that the Flag grob moved together with its Stem grob.

注意:Changing X-offset or Y-offset doesn’t always work as expected, see Aligning objects.

Now, let’s explain another pair of properties: X-extent and Y-extent. Each of them is a pair of numbers (internally, LilyPond calls this an interval), and they store a grob’s dimensions relative to its reference point. For example, X-extent equal to (-1 . 4) means that the left edge of the grob is 1 staff space to the left of its reference point, and the right edge is 4 staff spaces to the right from reference point, for a total width of 4 - (-1) = 4 + 1 = 5 staff spaces. Both numbers in an extent may be positive; for example, (2 . 3) is a valid extent: it means that the whole grob is on the right of its reference point, and the width of the grob is 3 - 2 = 1 staff space. Similarly, both numbers can be negative; these situations are quite unusual but won’t give LilyPond headaches. The most common situation (at least for X-extent) is that the first number is 0, which means that the reference point is on the left edge of the grob.

The previous example demonstrates this nicely: both the accent’s and the fermata’s left edge is left of the reference point; the same holds for the breve note head (we selected the 'altdefault note head style to make this better visible).

Now, suppose that we want to position a RehearsalMark grob so that its right edge is aligned with a bar line (by default, LilyPond horizontally centers the rehearsal mark). With X-offset equal to zero (i.e., its reference point is aligned on the parent, which is equal to the bar line in this situation), the RehearsalMark grob is placed like this:

{
  \override Score.RehearsalMark.X-offset = 0
  b4 b b b \mark "Twinkle" b b b b
}

[image of music]

So, we need to shift it. Remember what the second number in X-extent means? It’s the position of a grob’s right edge relative to its reference point. If we subtract this value from zero, we’ll get the x-offset we want:

{
  % value -10.4 found by trial and error
  \override Score.RehearsalMark.X-offset = -10.4
  b4 b b b \mark "Twinkle" b b b b
}

[image of music]

What if we wanted to center some grob on the reference point on its parent? That’s simple: calculate the displacement between a grob’s reference point and the center of its extent. Some examples:

There is already a function with a super-long name available that can do these calculations for us:

\override GrobName.X-offset =
  #ly:self-alignment-interface::x-aligned-on-self

and we only need to specify what alignment we want:

\override GrobName.self-alignment-X = #RIGHT

This code tells the procedure to find the displacement between a grob’s reference point and its right edge, and use it as the x-offset, which will result in the grob being right-aligned.

So, if you change a grob’s extent, you will affect how it will be aligned (because LilyPond will think that the grob’s dimensions are different):

{
  \override Score.RehearsalMark.X-extent = #'(0 . 8)
  \override Score.RehearsalMark.self-alignment-X = #RIGHT
  b4 b b b \mark "Twinkle" b b b b
}

[image of music]

Also, if a grob’s extent is empty (i.e., it’s not an interval pair), procedures like x-aligned-on-self won’t have any information about a grob’s dimensions, so they won’t be able to calculate an offset (they’ll just return value 0). In other words, a grob with an empty extent can only be ‘aligned’ on its reference point because there’s no other information that can be used for alignment:

{
  \override Score.RehearsalMark.X-extent = ##f
  b4 b b b \mark "Twinkle" b b b b
}

[image of music]

Notice that an empty extent and a zero extent result in the same positioning:

{
  \override Score.RehearsalMark.X-extent = #'(0 . 0)
  b4 b b b \mark "Twinkle" b b b b
}

[image of music]

However, an empty extent (or a zero extent, or any other extent) doesn’t prevent us from placing the grob at any location we want – we just can’t use alignment procedures for that. We can still specify any offset we want, and it will work as usual:

{
  \override Score.RehearsalMark.X-extent = ##f
  \override Score.RehearsalMark.X-offset = -10.4
  b4 b b b \mark "Twinkle" b b b b
}

[image of music]

Now, there is one more thing to keep in mind: a grob’s parent has its own dimensions, too, and we need to take them into account. For example, if we write

{ a'1 }
\addlyrics {
  \override LyricText.X-offset =
    #ly:self-alignment-interface::x-aligned-on-self
  \override LyricText.self-alignment-X = #CENTER
  nn
}

[image of music]

the LyricText grob will be centered, but on the reference point of its parent (i.e., the center of the syllable will be aligned to the reference point of the note head). If we want the center of the LyricText grob to be aligned with the center of its parent NoteHead grob, we have to use a different procedure: aligned-on-x-parent. It works very similar to x-aligned-on-self, but in addition to calculating an offset based on a grob’s own extent, it also uses the grob’s parent extent and computes positions relative to the center of the extent:

{ a'1 }
\addlyrics {
  \override LyricText.X-offset =
    #ly:self-alignment-interface::aligned-on-x-parent
  \override LyricText.self-alignment-X = #CENTER
  nn
}

[image of music]


LilyPond 学习手册 v2.25.14 (开发分支).