[prev in list] [next in list] [prev in thread] [next in thread]
List: lilypond-user
Subject: Re: Start, end, gradient of Glissando
From: Thomas Morley <thomasmorley65 () gmail ! com>
Date: 2021-10-30 13:54:21
Message-ID: CABsfGyWUm67GixbVWeyew-j215wQFdtT4yX9c1Z8v95OemW2SA () mail ! gmail ! com
[Download RAW message or body]
Am So., 24. Okt. 2021 um 18:19 Uhr schrieb Aaron Hill
<lilypond@hillvisions.com>:
>
> On 2021-10-24 8:05 am, Thomas Morley wrote:
> > Am So., 24. Okt. 2021 um 16:35 Uhr schrieb Aaron Hill
> >> Let me take a stab at converting the print routine to Scheme.
> >
> > Would be great !!
>
> Sorry for the delay... took me some time to figure out why there was an
> error with cross-staff right-side Y coordinate after porting the logic
> from C++. I think it's all working as expected, and I have added a few
> new test cases. (NOTE: I only have 2.22.0 here, so I had to fixup the
> version statement.) The one thing I did not include was adjusting the
> line ends for the arrows, but I assume the crosses would be best put at
> the arrow points anyway.
>
> There is something to note in the original logic. If the padding is
> large enough that the line spanner would disappear, then the stencil
> returned is null. I am also likewise returning the empty list instead
> of a point-pair, so the code that consumes the results would need to
> check for this case.
>
>
> -- Aaron Hill
Hi Aaron,
I now found the time to take a closer look.
There is a problem with cross-staff Glissando and non-zero paddings,
cause by taking relative coords in X/Y direction into account too
late.
Afaict, this needs to come first - changed.
Furthermore, to avoid the "Pythagorean theorem" I changed
(span-length (sqrt (+ (* span-dx span-dx) (* span-dy span-dy)))))
to
(span-length (ly:length span-dx span-dy)))
Some other questions, (I attach the file with my comments and TODOs,
etc as well):
(1) You do
(common-x (ly:grob-common-refpoint grob
(ly:grob-common-refpoint
(ly:spanner-bound grob LEFT)
(ly:spanner-bound grob RIGHT) X) X))
Though, the inner ly:grob-common-refpoint returns already the System
grob, why searching again?
Furthermore, a bit later there's
(system (ly:grob-system grob))
which again will return the System grob.
Is there any case where those three are not equal?
(2) There is
(dy (if simple-y?
0
(ly:grob-relative-coordinate grob common-y Y)))
Though if `grob' and `common-y' are equal it returns always zero, afaict.
Is there any example where they are not equal?
(3) Why take 'simple-Y into account?
Well, it's true per default for Glissando, alas it makes no difference afaict.
Btw, we don't have any regtest for it
Many thanks again,
Harm
["start-end-gradient-03b-harm.ly" (text/x-lilypond)]
\version "2.22.0" % "2.23.3"
%% rewritten by Aaron Hill, many thanks!
%% https://lists.gnu.org/archive/html/lilypond-user/2021-10/msg00354.html
%% Comments/TODOs by Harm
\paper {
indent = 0
ragged-right = ##f
line-width = 120
}
\layout {
\context {
\Voice
\override Glissando.layer = 1000
\override Glissando.bound-details.left.padding = 5
\override Glissando.bound-details.right.padding = 5
\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* ((simple-y? (and (ly:grob-property grob 'simple-Y)
(not (ly:grob-property grob 'cross-staff))))
(lbi (ly:grob-property grob 'left-bound-info))
(rbi (ly:grob-property grob 'right-bound-info))
;;;;;;;;;;;
;; TODO (1)
;;;;;;;;;;;
;; Common refpoint of the spanner-bounds is already grob System
;; Why searching again, doesn't it will return grob System again?
;; Is there any ly-counter-example?
;; See the test-code below inside `pretty-print'
(common-x (ly:grob-common-refpoint grob
(ly:grob-common-refpoint
(ly:spanner-bound grob LEFT)
(ly:spanner-bound grob RIGHT) X) X))
(scaling (magstep (ly:grob-property grob 'font-size 0)))
(left-padding (ly:assoc-get 'padding lbi 0))
(left-stencil (ly:assoc-get 'stencil lbi #f))
(left-common-y (ly:assoc-get 'common-y lbi grob))
(right-padding (ly:assoc-get 'padding rbi 0))
(right-stencil (ly:assoc-get 'stencil rbi #f))
(right-common-y (ly:assoc-get 'common-y rbi grob))
(common-y (ly:grob-common-refpoint left-common-y right-common-y Y))
(normalized-endpoints
(ly:grob-property grob 'normalized-endpoints '(0 . 1)))
(span-left-x (ly:assoc-get 'X lbi 0))
(span-left-y (ly:assoc-get 'Y lbi 0))
(span-right-x (ly:assoc-get 'X rbi 0))
(span-right-y (ly:assoc-get 'Y rbi 0)))
;; Take relative coords in X/Y direction into account.
;; This needs to come before other modifications of x/y values!
;; Especially `dy-right' is important for cross-staff spanners
(let* ((dx (ly:grob-relative-coordinate grob common-x X))
;;;;;;;;;;;
;; TODO (2)
;;;;;;;;;;;
;; Do we need to calculate `dy' at all?
;; Will (ly:grob-relative-coordinate grob common-y Y) ever be not zero, if
;; grob and common-Y are equal?
;; Is it possible at all they are ever unequal? ly-counter-example?!
(dy (if simple-y?
0
(ly:grob-relative-coordinate grob common-y Y)))
;;;;;;;;;;;
;; TODO (1)
;;;;;;;;;;;
;; Why call (ly:grob-system grob)?
;; Afaict, it's the same as `common-x' form above (and see TODO there and
;; test-code inside of `pretty-print' below)
(system (ly:grob-system grob))
(dy-right (ly:grob-relative-coordinate grob system Y)))
;; test-code
;(pretty-print
; (let* ((bounds-refpt-X
; (ly:grob-common-refpoint
; (ly:spanner-bound grob LEFT)
; (ly:spanner-bound grob RIGHT)
; X))
; (common-X
; (ly:grob-common-refpoint
; grob
; bounds-refpt-X
; X))
; (sys (ly:grob-system grob))
; (lst (list bounds-refpt-X common-X sys))
; )
; (delete-duplicates lst equal?)
; )
;)
(set! span-left-x (- span-left-x dx))
(set! span-left-y (- span-left-y dy))
(set! span-right-x (- span-right-x dx))
(set! span-right-y (- span-right-y dy dy-right)))
;;;;;;;;;;;
;; TODO (3)
;;;;;;;;;;;
;; Is there any need to modify `span-left-y' and `span-right-y' wrt to
;; `simple-y?'
;; In all tested cases `span-left-y' and `span-right-y' keep their value, see:
;;
; (pretty-print
; (list
; (ly:grob-relative-coordinate left-common-y common-y Y)
; (ly:grob-relative-coordinate right-common-y common-y Y)
; )
; )
;; Is there any counter-example?
(if (not simple-y?)
(begin
(set! span-left-y (+ span-left-y
(ly:grob-relative-coordinate left-common-y common-y Y)))
(set! span-right-y (+ span-right-y
(ly:grob-relative-coordinate right-common-y common-y Y)))))
;; For broken Spanner modify `span-left-y' and `span-right-y' 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 `span-left-y' and `span-right-y' stay unchanged then
(let ((y-length (- span-right-y span-left-y)))
(set! span-left-y (+ span-left-y
(* (car normalized-endpoints) y-length)))
(set! span-right-y (- span-right-y
(* (- 1 (cdr normalized-endpoints)) y-length))))
;; Take into account:
;; - padding vaues
;; - (text-)stencils
(let* ((span-dx (- span-right-x span-left-x))
(span-dy (- span-right-y span-left-y))
;; Avoid "Pythagorean theorem", use ly:length instead
(span-length (ly:length span-dx span-dy)))
(if (> (+ left-padding right-padding) span-length)
;; If padding is large enough that the spanner disappears, return '()
;; NB needs to be checked by the caller of this procedure
'()
(let* (;; the cosinus of the enclosed angle
(grad-dx (/ span-dx span-length))
;; the sinus of the enclosed angle
(grad-dy (/ span-dy span-length)))
;; cosinus and sinus of the enclosed angle are constants, where the
;; x and y-values are due to radius 1
;; To respect left/right-padding values, which are on that radius,
;; we need to modify our span-left/right-x/y values:
;; Simply multiply the relevant padding with (co)sinus, i.e.
;; `grad-dx' resp. `grad-dy' following the "Intercept theorem"
;; (Don't forget `scaling' for possible (text-)stencils).
;;
(set! span-left-x
(+ span-left-x (* left-padding scaling grad-dx)))
(set! span-left-y
(+ span-left-y (* left-padding scaling grad-dy)))
(set! span-right-x
(- span-right-x (* right-padding scaling grad-dx)))
(set! span-right-y
(- span-right-y (* right-padding scaling grad-dy)))
;; If a (text-)stencil is present at start/end of the spanner,
;; the relevant x/x values needs to get modified
(if (and (ly:stencil? left-stencil)
(not (ly:stencil-empty? left-stencil)))
(let ((factor
(/ (cdr (ly:stencil-extent left-stencil X)) grad-dx)))
(set! span-left-x (+ span-left-x (* factor grad-dx)))
(set! span-left-y (+ span-left-y (* factor grad-dy)))))
(if (and (ly:stencil? right-stencil)
(not (ly:stencil-empty? right-stencil)))
(let ((factor
(/ (car (ly:stencil-extent right-stencil X)) grad-dx)))
(set! span-right-x (+ span-right-x (* factor grad-dx)))
(set! span-right-y (+ span-right-y (* factor grad-dy)))))
(cons (cons span-left-x span-left-y)
(cons span-right-x span-right-y))))))))
#(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) magenta)))))
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Examples
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% simple-Y
{
\override Glissando.stencil = #gliss-stencil-with-crosses
e''1\glissando s2 e'
}
%% Simple
{
\override Glissando.stencil = #gliss-stencil-with-crosses
e''1\glissando s2 e'
}
%% Padding
{
\override Glissando.stencil = #gliss-stencil-with-crosses
\override Glissando.bound-details.left.padding = #3
\override Glissando.bound-details.right.padding = #5
e''1\glissando s2 e'
}
%% Stencils
{
\override Glissando.stencil = #gliss-stencil-with-crosses
\override Glissando.font-size = #3
\override Glissando.bound-details.left.text =
\markup \vcenter \box \left-align "lorem"
\override Glissando.bound-details.right.text =
\markup \vcenter \box \right-align "ipsum"
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
}
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic