lilypond-user
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: TupletBrackets edge thickness


From: Thomas Morley
Subject: Re: TupletBrackets edge thickness
Date: Sun, 11 Aug 2024 23:19:58 +0200



Am Sa., 10. Aug. 2024 um 19:11 Uhr schrieb Lukas-Fabian Moser <lfm@gmx.de>:

Hi Kieren,

Left to do: We probably also should modify the extents of the resulting stencil to avoid collisions...
If the thickness of the edge lines are expanded *inwards*, wouldn’t the original extent still be accurate enough to use?

Yes, good idea. But then we see that for thick lines, LilyPond's rounded line tips become a problem (actually, the problem wouldn't be just as serious with box-formed line tips):

So we should probably replace the edge line by a box, more precisely: by a polygon with the correct slope at least on the connecting side. Sigh.

Re-posting the source nevertheless, since in my first attempt I forgot that TupletBrackets can point upwards or downwards.

\version "2.24.0"

#(define (list-add! lst k x)
   (list-set! lst k (+ (list-ref lst k) x)))

{
  \override TupletBracket.stencil =
  #(grob-transformer
    'stencil
    (lambda (grob stil)
      (let*
       ((expr (ly:stencil-expr stil))
        (xext (ly:stencil-extent stil X))
        (yext (ly:stencil-extent stil Y))
        (lines (cdaddr expr))
        (right (first lines))
        (left (second lines))
        (thick (second right))
        (dir (- (ly:grob-property grob 'direction)))
        (new-thick 0.7)  ;; adjust at will
        (offset (/ (- new-thick thick) 2)))
       
       (list-set! right 1 new-thick)
       (list-add! right 2 (- offset))         ; x1
       (list-add! right 3 (* dir offset))     ; y1
       (list-add! right 4 (- offset))         ; x2

       (list-set! left 1 new-thick)
       (list-add! left 2 offset)              ; x1
       (list-add! left 3 (* dir offset))      ; y1
       (list-add! left 4 offset)              ; x2

       (ly:make-stencil expr xext yext))))

  \tupletDown
  \tuplet 3/2 { c'4 d' c''' }
  \tupletUp
  \tuplet 3/2 { c'4 d' e' }
}

And of course: The proper way to handle all of this would be to just swallow the pill and re-implement the a modified TupletBracket stencil in Scheme.

Lukas


Here my take on it.
Some effort is done to identify the wings drawing lines: not going for the position in the stencil-list, but for matching their height with the relevant grob edge-height. Hopefully safer...

\version "2.24.3"

#(define (lists-map function ls)
  "Apply @var{function} to @var{ls} and all of it sublists.
First it recurses over the children, then the function is applied to
@var{ls}."
    (if (list? ls)
        (set! ls (map (lambda (y) (lists-map function y)) ls))
        ls)
    (function ls))

#(define (tuplet-bracket::line-parts grob stencil)
  "Examine @code{TupletBracket.stencil), accumulate lines used to draw
@code{TupletBracket}, divided into wings and horizontal lines."
  (if (ly:stencil-empty? stencil)
      '()
      (let* ((lines '())
             (edge-height (ly:grob-property grob 'edge-height))
             (stil-expr (ly:stencil-expr stencil)))

        ;; accumulate the bracket-drawing lines in `lines`
        (when (pair? stil-expr)
          (lists-map
            (lambda (l)
              (when (and (list? l)
                         (eq? (list-ref l 0) 'draw-line)
                         ;; Broken TupletBracket may have collapsed wings,
                         ;; don't catch them. Deal with them when this procedure
                         ;; is called.
                         (not (zero?
                                (- (- (list-ref l 2) (list-ref l 4))
                                   (- (list-ref l 3) (list-ref l 5))))))
                (set! lines (cons l lines)))
              l)
            stil-expr))

        (call-with-values
          (lambda ()
            (partition
              (lambda (l)
                (let ((height (- (list-ref l 3) (list-ref l 5))))
                  ;; TODO looking at height is probably not safe enough.
                  ;; Avoid rounding issues
                  (or
                     (> 0.0000001
                        (abs (- (abs height) (abs (car edge-height)))))
                     (> 0.0000001
                        (abs (- (abs height) (abs (cdr edge-height))))))))
              lines))
          (lambda (x y)
            (list (cons 'wings x) (cons 'horizontals y)))))))

#(define (tuplet-bracket::wing-thickness wing-thickness)
  "Examine @code{TupletBracket.stencil), replace the wings by a polygon
mimicking enlarged thickness."
 (grob-transformer 'stencil
  (lambda (grob orig)
   (let* ((parts (tuplet-bracket::line-parts grob orig))
          (raw-wings (assoc-get 'wings parts)))
     (if (not (pair? raw-wings))
         orig
         (let* (
          (horizontals (assoc-get 'horizontals parts))
          (slopes
           (map
            (lambda (l)
              (/ (- (list-ref l 5) (list-ref l 3))
                 (- (list-ref l 4) (list-ref l 2))))
            horizontals))
          (wings
           (cond ((middle-broken-spanner? grob) '(#f #f))
                 ((first-broken-spanner? grob)
                   (append raw-wings (list #f)))
                 ((end-broken-spanner? grob)
                   (cons #f raw-wings))
                 (else raw-wings)))
          (grob-thick
           (ly:grob-property grob 'thickness))
          (staff-line-thick
           (ly:staff-symbol-line-thickness (ly:grob-object grob 'staff-symbol)))
          (thick (* grob-thick staff-line-thick))
          (edge-height (ly:grob-property grob 'edge-height))
          (shorten-pair (ly:grob-property grob 'shorten-pair '(0 . 0)))
          (dir (ly:grob-property grob 'direction)))

    (ly:make-stencil
     (lists-map
      (lambda (l)
       (cond
        ((equal? l (car wings))
          (let* ((start-x (list-ref l 2))
                 (start-y (+ (list-ref l 3) (* wing-thickness (car slopes))))
                 (shorten-pair (car shorten-pair))
                 (edge-height (car edge-height)))
            `(polygon
              ,(list
                start-x (list-ref l 3)
                (+ start-x wing-thickness) start-y
                (+ start-x wing-thickness) (+ start-y (* -1 dir edge-height))
                start-x (+ (list-ref l 3) (* dir -1 edge-height)))
              ;; take `thick` as blot-diameter to match rounded line ends
              ,thick
              #t)))
        ((equal? l (cadr wings))
          (let* ((end-x (list-ref l 2))
                 (start-x (- end-x wing-thickness))
                 (start-y (* start-x (cadr slopes)))
                 (end-y (list-ref l 5))
                 (edge-height (cdr edge-height)))
            `(polygon
               ,(list
                 end-x end-y
                 end-x (- end-y (* dir -1 edge-height))
                 start-x start-y
                 start-x (+ start-y (* dir -1 edge-height)))
               ,thick
               #t)))
        (else l)))
      (ly:stencil-expr orig))
     (ly:stencil-extent orig X)
     (ly:stencil-extent orig Y))))))))

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

\layout {
  \override TupletBracket.stencil = #(tuplet-bracket::wing-thickness 1)
}

{
  \tuplet 3/2 { b4 b b } \tuplet 3/2 { b'' b b } \tuplet 3/2 { b b b'' }
  \tupletDown
  \tuplet 3/2 { b4 b b } \tuplet 3/2 { b'' b b } \tuplet 3/2 { b b b'' }
}

{
  \tuplet 3/2 { b1 b''2 \break b4 b \break b''2 b }
}


Best,
  Harm

reply via email to

[Prev in Thread] Current Thread [Next in Thread]