Am So., 24. Okt. 2021 um 16:35 Uhr schrieb Aaron Hill
<lilyp...@hillvisions.com>:
>
> On 2021-10-24 6:22 am, Thomas Morley wrote:
> > Though, how could I have found it myself?
> > My lack of C++-knowledge hinders me to understand the "logic from
> > Line_spanner::print". I usually learn things from looking at
> > scheme-codings.
>
> Not sure it would have been clear without digging into the print
> function.  For reference, here are the relevant lines:
>
> ////
>    Interval normalized_endpoints = from_scm (get_property (me,
> "normalized-endpoints"), Interval (0, 1));
>    Real y_length = span_points[RIGHT][Y_AXIS] -
> span_points[LEFT][Y_AXIS];
>
>    span_points[LEFT][Y_AXIS] += normalized_endpoints[LEFT] * y_length;
>    span_points[RIGHT][Y_AXIS] -= (1 - normalized_endpoints[RIGHT]) *
> y_length;
> ////

Yeah, I found them already, but I have even difficulties to decipher
what's a varable, what's an operation, what's a procedure ...

> > But there is none in our source using 'normalized-endpoints, apart
> > from setting it in some grob-definitions.
> > The description reads: "Represents left and right placement over the
> > _total_ spanner, where the _width_ of the spanner is normalized
> > between 0 and 1."
> > I think the wording is misleading, at least "total" means the unbroken
> > spanner for me, thus I never considered to look at it for broken
> > spanners.
> > The word "width" means the extent in X-axis direction, again no reason
> > to look at it for extents in Y-axis.
>
> You are right that "width" is talking about the X extent, but "total"
> does not just mean an unbroken spanner but the entire spanner, broken or
> otherwise.

Well, my first thought about it was different.
Maybe I find a better wording, then I'll put up a patch.

> The resulting normalized values are in essence percentages
> of the total width if you were to lay each broken element end-to-end.
> For example, if a spanner is broken into two parts of equal size, then
> you should see normalized-endpoints as the intervals [0, 0.5] and [0.5,
> 1].
>
>
> > P.S.
> > While the Y-values are fixed now, I found some flaw, if left/right
> > padding is not zero. At least for broken or cross-staff Glissando.
> > I'll continue research..., unless someone has another hint?

Meanwhile I found the culprit with non-zero paddings, see attached.

> Yup, there's more code in Line_spanner::print that factors in the
> padding values.  It is perhaps harder to locate because the variable was
> named "gaps".  And it turns out there is more than just padding that
> will affect your calculation.  Try setting a stencil in either
> bound-details, as that will also shorten the effective spanner line.
> Arrows, however, seem to overlay on the line without changing its
> length.
>
> Let me take a stab at converting the print routine to Scheme.

Would be great !!

> -- Aaron Hill

Best,
  Harm
\version "2.23.3"

\paper {
  indent = 0
  ragged-right = ##f
  line-width = 120
}

\layout {
  \context {
    \Voice
    \override Glissando.layer = 1000
    \override Glissando.bound-details.left.padding =  15
    \override Glissando.bound-details.right.padding = 15
    \override Glissando.breakable = ##t
  }
}

%% cross stensil
#(define*
   (make-cross-stencil coords #:optional (thick 0.1) (sz 0.2))
   (ly:stencil-add
     (make-line-stencil
       thick
       (- (car coords) sz)
       (- (cdr coords) sz)
       (+ (car coords) sz)
       (+ (cdr coords) sz))
     (make-line-stencil
       thick
       (- (car coords) sz)
       (+ (cdr coords) sz)
       (+ (car coords) sz)
       (- (cdr coords) sz))))

%% glissando stencil
#(define glissando-stencil-proc (lambda (grob) (ly:line-spanner::print grob)))

%% get start/end points
#(define gliss-data
  (lambda (grob)
    (let* ((left-bound-info (ly:grob-property grob 'left-bound-info))
           (Y-left (assoc-get 'Y left-bound-info))
           (X-left (assoc-get 'X left-bound-info))
           (left-padding (assoc-get 'padding left-bound-info))
           (right-bound-info (ly:grob-property grob 'right-bound-info))
           (Y-right (assoc-get 'Y right-bound-info))
           (X-right (assoc-get 'X right-bound-info))
           (right-padding (assoc-get 'padding right-bound-info))
           (sys (ly:grob-system grob))
           (line-thickness (ly:staff-symbol-line-thickness grob))
           (grob-thickness (ly:grob-property grob 'thickness #f))
           (thick (or grob-thickness line-thickness))
           (grob-relative-coord
             (ly:grob-relative-coordinate grob sys X))
           (current-y-coord (ly:grob-relative-coordinate grob sys Y))
           (normalized-endpoints (ly:grob-property grob 'normalized-endpoints))
           ;; Return the difference between highest and lowest Y
           (Y-length (- Y-right Y-left))
           ;; For broken Glissando modify `Y-left' and `Y-right' with scaled
           ;; parts of `Y-length'. The scaling factors are taken from the pair
           ;; `normalized-endpoints', car for left, cdr for right.
           ;; For unbroken Glissandi `normalized-endpoints' defaults to '(0 . 1)
           ;; and actually unchanged `Y-left' and `Y-right' are used.
           (normal-Y-left
             (+ Y-left (* (car normalized-endpoints) Y-length)))
           (normal-Y-right
             (- Y-right (* (- 1 (cdr normalized-endpoints)) Y-length)))
           (gradient
             (/
                (- (- normal-Y-right normal-Y-left current-y-coord))
                (- (- X-left grob-relative-coord)
                   (- X-right grob-relative-coord))))
           ;; left/right-padding are values representing parts of the actual
           ;; line, i.e. not X, or Y-values but their magnitude
           ;; Thus we get the angel and calculate the x- and y-part as a pair,
           ;; then we use the part on the X-axis to find the needed coords
           (angle (ly:angle 1 gradient))
           (left-padding-x
             (car (ly:directed angle left-padding)))
           (left-padding-y
             (* gradient left-padding-x))
           (right-padding-x
             (car (ly:directed angle right-padding)))
           (right-padding-y
             (* gradient right-padding-x))
           (start-coord
             (cons
               (- X-left grob-relative-coord (- left-padding-x) (/ thick 2))
               (+ normal-Y-left left-padding-y)))
           (end-coord
             (cons
               (- X-right grob-relative-coord right-padding-x (- (/ thick 2)))
               (- normal-Y-right right-padding-y current-y-coord))))
      (cons start-coord end-coord))))

#(define gliss-stencil-with-crosses
  (lambda (grob)
    (let* ((cross-coords (gliss-data grob)))
      (ly:stencil-add
        ;; left cross
        (stencil-with-color
          (make-cross-stencil (car cross-coords) 0.2 0.2) blue)
        ;; right cross
        (stencil-with-color
          (make-cross-stencil (cdr cross-coords) 0.2 0.2) red)
        ;; glissando
        (stencil-with-color (glissando-stencil-proc grob) green)))))

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Examples
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%% Simple

{
  \override Glissando.stencil = #gliss-stencil-with-crosses
  e''1\glissando s2 e'
}

%% cross-staff

\new PianoStaff
  <<
    \new Staff = "top"
      \with {
        \override VerticalAxisGroup.staff-staff-spacing.padding = 30
      }
      \relative c'' {
        \override Glissando.stencil = #gliss-stencil-with-crosses
        c1\glissando
        \change Staff = "bottom"
        s2
        g,,2
      }

    \new Staff = "bottom" { \clef "bass" s1*2 }
  >>

%% with line break

{
  \override Glissando.stencil = #gliss-stencil-with-crosses

  e'''1\glissando
  \break
  s2 \once \override NoteColumn.glissando-skip = ##t c''
  \break
  s2 b

  \break

  b1\glissando
  \break
  s2 \once \override NoteColumn.glissando-skip = ##t c''
  \break
  s2 e'''
}

Reply via email to