Le 09/04/2021 à 19:12, Kevin Barry a écrit :
On Fri, Apr 09, 2021 at 11:49:48AM +0200, Jean Abou Samra wrote:
Or did you observe the same phenomenon without cross-staff
beams, Kevin?
The same procedure (consider_auto_knees) is called in every case. I
presume if there is only one staff involved the extent calculations will
(as you suggest) pull in less grobs. It's true the bug I worked on
involved cross-staff stems so I probably wasn't specifically checking
the differences when that wasn't the case.
Kevin
Yes, I am pretty sure about that. You mention this line:
head_extents += stem->pure_relative_y_coordinate (common, 0,
INT_MAX); Grob::pure_relative_y_coordinate is in grob.cc:
Real Grob::pure_relative_y_coordinate (Grob const *refp, vsize start,
vsize end) { if (refp == this) return 0.0; Real off = 0; if
(dim_cache_[Y_AXIS].offset_) { if (from_scm<bool>
(get_property (this, "pure-Y-offset-in-progress")))
programming_error ("cyclic chain in pure-Y-offset callbacks"); off
= *dim_cache_[Y_AXIS].offset_; } else { SCM proc =
get_property_data (this, "Y-offset"); dim_cache_[Y_AXIS].offset_ =
0; set_property (this, "pure-Y-offset-in-progress", SCM_BOOL_T);
off = from_scm<double> (call_pure_function (proc,
scm_list_1 (self_scm
()), start, end),
0.0); del_property (this,
"pure-Y-offset-in-progress"); dim_cache_[Y_AXIS].offset_.reset ();
} /* we simulate positioning-done if we are the child of a
VerticalAlignment, but only if we don't have a cached offset. If we
do have a cached offset, it probably means that the Alignment was
fixed and it has already been d. */ if (Grob *p = get_y_parent
()) { Real trans = 0; if (has_interface<Align_interface>
(p) && !dim_cache_[Y_AXIS].offset_) trans =
Align_interface::get_pure_child_y_translation (p, this, start, end);
return off + trans + p->pure_relative_y_coordinate (refp, start,
end); } return off; } This triggers
Align_interface::get_pure_child_y_translation when a VerticalAlignment
is in the parent chain. Now, doing some debugging:
\version "2.22.0" \layout { \context { \Voice \override
Beam.after-line-breaking = #(lambda (grob) (let* ((stems
(ly:grob-object grob 'stems)) (refpoint
(ly:grob-common-refpoint-of-array grob stems Y))) (ly:message
"Refpoint: ~s" refpoint))) } } << \new Staff
= "up" \relative c'' { a8 g f e a8 g f e d c \change Staff = "down"
b a } \new Staff = "down" { \clef bass s1. } >> This prints
Refpoint: #<Grob VerticalAlignment >
Refpoint: #<Grob VerticalAxisGroup >
Refpoint: #<Grob VerticalAxisGroup > Two VerticalAxisGroup grobs and a
VerticalAlignment, which means that the VerticalAlignment corresponds to
the cross-staff beam. In align-interface.cc:
Real Align_interface::get_pure_child_y_translation (Grob *me, Grob *ch,
vsize start, vsize end) { extract_grob_set (me, "elements", all_grobs);
vector<Real> translates = get_pure_minimum_translations (me, all_grobs,
Y_AXIS, start, end); if (translates.size ()) { for (vsize i = 0; i <
all_grobs.size (); i++) if (all_grobs[i] == ch) return translates[i]; }
else return 0; programming_error ("tried to get a translation for
something that is no child of mine"); return 0; } which processes all
the grobs of the VerticalAlignment. That sounds reasonable: the beam
needs to know how much space there is between the two staves to
determine if it should be kneed. But of course, pure calculations on all
elements of the VerticalAlignment can mean quite a lot, which does sound
prone to circular dependencies. Best, Jean