Deutschsprachiges LilyPond-Forum

Allgemeine Fragen und Probleme => Fragen und Probleme aller Art => Thema gestartet von: Manuela am Samstag, 8. April 2023, 13:44

Titel: Markup geschert spiegeln funktioniert nicht (ganz) bei Score-Markup
Beitrag von: Manuela am Samstag, 8. April 2023, 13:44
Ich habe den Code aus diesem Thread (https://lilypondforum.de/index.php/topic,1216.0.html) erweitert.

Das funktioniert prima, solange das Markup ein simpler Text ist. Bei einem Score-Markup stimmt es nicht, woran liegt das?
\version "2.23.5"

% LSR workaround:
#(set! paper-alist (cons '("snippet" . (cons (* 160 mm) (* 75 mm))) paper-alist))
\paper {
  #(set-paper-size "snippet")
  tagline = ##f
  #(include-special-characters)
  indent = #0
  ragged-right = ##t
}

#(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-markup-command (mirror layout props arg ang col gap)
   ;; skewes the input markup at a certain angle, stencil vanishes at 90 degrees
   ;; takes three arguments
   ;; arg: markup to skew
   ;; ang: skewing angle degrees
   ;; type: true/false
   ;; if true the original height is preserved, otherwise it decreases with cos ang
   (markup?  number? color? number?)
   (let* ((deg-rad-factor (/ PI 180))
          (par #f)
          (distance (* -1 gap))
          (half-ang (* 0.5 ang))
          (sin-part (sin (* deg-rad-factor half-ang)))
          (cos-part (cos (* deg-rad-factor half-ang)))
          (px (- cos-part sin-part))
          (py (+ cos-part sin-part))
          ; Overall Matrix: xx = 1.0    xy
          ;                 yx = 0.0    yy
          (xy (if par (tan (* deg-rad-factor ang))
                  (sin (* deg-rad-factor ang))))
          (yy (if par 1.0 (cos (* deg-rad-factor ang))))
          ; input markup's stencil and extent
          (stil (interpret-markup layout props arg))
          (ext-x (ly:stencil-extent stil X))
          (ext-y (ly:stencil-extent stil Y))
          (stil-expr (ly:stencil-expr stil))
          (get-caddr-if-condition
           (lambda (e)
             (if (and (list? e) (member 'color e))
                 ;; the stencil-expr of a colored stencil is of type
                 ;; (list 'color (list r g b) (list rest-of-stencil-expr))
                 ;; Thus we can be sure that (caddr e) is valid
                 ;; Even for an empty-stencil it evaluates to '()
                 (caddr e)
                 e)))
          (colored-stil
           (stencil-with-color
            (ly:make-stencil
             (lists-map get-caddr-if-condition stil-expr)
             ext-x
             ext-y)
            col))
          (xo1 (car ext-x))
          (xo2 (cdr ext-x))
          (yo1 (car ext-y))
          (yo2 (cdr ext-y))
          ; four edge points transformed by that matrix
          (xp1 (+ xo1 (* xy yo1)))
          (yp13 (* yy yo1))
          (xp2 (+ xo1 (* xy yo2)))
          (yp24 (* yy yo2))
          (xp3 (+ xo2 (* xy yo1)))
          (xp4 (+ xo2 (* xy yo2)))
          ; new extent
          (xmin (min xp1 xp2 xp3 xp4))
          (xmax (max xp1 xp2 xp3 xp4))
          (ymin (min yp13 yp24))
          (ymax (max yp13 yp24))
          (stil-3 (ly:stencil-rotate-absolute colored-stil 45.0 0.0 0.0))
          (stil-4 (ly:stencil-scale stil-3 px py))
          (stil-5 (ly:stencil-outline (ly:stencil-rotate-absolute stil-4 (- -45.0 half-ang) 0.0 0.0)
                                      (make-filled-box-stencil (cons xmin xmax) (cons ymin ymax))))
          (stil-with-mirror (ly:stencil-add (ly:stencil-translate (ly:stencil-scale stil-5 1 -1) (cons 0 (* -1 gap))) stil))
          )
     ;      (write-me "degrad " deg-rad-factor)
     ;      (write-me "180/PI " (/ PI 180))
     stil-with-mirror
     ))

hello = \markup \override #'(box-padding . 0.0) \with-color #darkgreen \box
\with-color #black \fontsize #6 "Hello world!"

hellox = \markup \override #'(box-padding . 0.0) \with-color #darkgreen \box
\score {
  \relative { c'4 d e f g2 a8 g f16 e }
  \layout {
    ragged-right = ##t
    line-width = #60
    \context {
      \Score
      \override NonMusicalPaperColumn.line-break-permission = ##f
      \override SpacingSpanner.common-shortest-duration = #(ly:make-moment 1/1)
    }
  }
}
\markup \line {
  \left-column {
    \hello
  }
  \left-column {
    \mirror \hello #45 #(x11-color 'LightCoral) #1
  }
  \left-column {
    \mirror \hello #45 #(x11-color 'MediumSpringGreen) #2
  }
}
\markup \line {
  \left-column {
    \mirror \hellox #-70 #(x11-color 'DarkSlateGrey) #10
  }
  \left-column {
    \mirror \hellox #-30 #(x11-color 'MediumAquamarine) #7
  }
}
Titel: Antw:Markup geschert spiegeln funktioniert nicht (ganz) bei Score-Markup
Beitrag von: Arnold am Freitag, 14. April 2023, 20:20
Hallo Manuela,

das liegt an der Position, wo der Koordinatenursprung des Markups liegt - mindestens bei positiven Scherwinkeln.
Kann z. Bsp. graphisch angezeigt werden durch:
\markup \overlay {
  \BisherigesMarkup
  \with-color #magenta \path #0.2 #'((moveto 2 1) (lineto 0 0) (lineto 1 2))
}
Bei einzeiligen Texten liegt der links auf der Text-Grundlinie. Bei einer Notenzeile liegt der am linken Anfang der mittleren Notenzeilenlinie, also deutlich entfernt vom unteren Rand.

Interessieren Dich genauere Zahlenwerte, dann kannst Du diese Markup-Funktion zwischenschalten, die Ausdehnung wird (zusammen mit den String als Kennzeichen) in der Standardausgabe angegeben. Leicht zu sehen, wenn Du in der Kommandozeile kompilierst, sonst frag die Nutzer welche LILYPOND so wie Du starten.
#(define-markup-command (dump-dimension layout props text arg)
  (string? markup?)
  (let* ((stil (interpret-markup layout props arg))
         (extx (ly:stencil-extent stil X))
         (exty (ly:stencil-extent stil Y)))
   (for-each display (list "\nExtent of '" text "': "
    (ly:number->string (car extx)) ".." (ly:number->string (cdr extx)) " / "
    (ly:number->string (car exty)) ".." (ly:number->string (cdr exty)) "\n"))
   stil))

Wenn Du in Deiner Routine nach xmin, xmax, ymin und ymax noch ein extragap berechnest
(extra-gap (- (+ ymin yo1)))d.h. die Untergrenze des Ursprungs-Markups (negativ) mit der Untergrenze der Scherung (auch noch negativ, wird quasi positiv orientiert nachdem Du die Scherung an der X-Achse gespiegelt hast) addierst, und dessen Vorzeichen umkehrst, bekommst Du einen (zusätzlichen) Abstandswert.
Den kannst Du dann in Deinem stencil-translate berücksichtigen:
(cons 0 (* -1 (+ gap extra-gap)))
Arnold.
Titel: Antw:Markup geschert spiegeln funktioniert nicht (ganz) bei Score-Markup
Beitrag von: Arnold am Samstag, 15. April 2023, 07:16
Hallo Manuela,

ich hoffe, die Kommentare im Quelltext genügen.
\version "2.24.1"

% LSR workaround:
#(set! paper-alist (cons '("snippet" . (cons (* 160 mm) (* 75 mm))) paper-alist))
\paper {
  #(set-paper-size "snippet")
  tagline = ##f
  #(include-special-characters)
  indent = #0
  ragged-right = ##t
}

#(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-markup-command (mirror layout props arg ang col gap)
  ;; skewes the input markup at a certain angle, stencil vanishes at 90 degrees
  ;; takes three arguments
  ;; arg: markup to skew
  ;; ang: skewing angle degrees
  ;; type: true/false
  ;; if true the original height is preserved, otherwise it decreases with cos ang
  (markup?  number? color? number?)
  (let* ((par #f)                ; fixed!
          ; (distance (* -1 gap)) ; unused!
          (half-ang (* 0.5 ang))
          (ang-dir (ly:directed ang))
          (cos-ang (car ang-dir))
          (sin-ang (cdr ang-dir))
          (half-dir (ly:directed half-ang))
          (sin-part (cdr half-dir))
          (cos-part (car half-dir))
          (px (- cos-part sin-part))
          (py (+ cos-part sin-part))
          ; input markup's stencil, expression and extent
          (stil (interpret-markup layout props arg))
          (ext-x (ly:stencil-extent stil X))
          (ext-y (ly:stencil-extent stil Y))
          (xo1 (car ext-x))
          (xo2 (cdr ext-x))
          (yo1 (car ext-y))
          (yo2 (cdr ext-y))
          (stil-expr (ly:stencil-expr stil))
          ; for color change ...
          (get-caddr-if-condition
          (lambda (e)
            (if (and (list? e) (member 'color e))
                ;; the stencil-expr of a colored stencil is of type
                ;; (list 'color (list r g b) (list rest-of-stencil-expr))
                ;; Thus we can be sure that (caddr e) is valid
                ;; Even for an empty-stencil it evaluates to '()
                (caddr e)
                e)))
          (colored-stil
          (stencil-with-color
            (ly:make-stencil
            (lists-map get-caddr-if-condition stil-expr)
            ext-x
            ext-y)
            col))
          ; Overall Matrix: xx = 1.0    xy
          ;                yx = 0.0    yy
          (xy (if par (/ sin-ang cos-ang) ; you remember: tan(x) = sin(x) / cos(x)
                  sin-ang))
          (yy (if par 1.0 cos-ang))
          ; four edge points transformed by that matrix
          (xp1 (+ xo1 (* xy yo1)))
          (yp13 (* yy yo1))
          (xp2 (+ xo1 (* xy yo2)))
          (yp24 (* yy yo2))
          (xp3 (+ xo2 (* xy yo1)))
          (xp4 (+ xo2 (* xy yo2)))
          ; new extent
          (xmin (min xp1 xp2 xp3 xp4))
          (xmax (max xp1 xp2 xp3 xp4))
          (ymin (min yp13 yp24))
          (ymax (max yp13 yp24))
          ; transformed x coordinate distance of lower left edge,
          ; some extra amount '0.5 * gap' added to let the bend line appear inside the gap
          (x-low-dist (* xy (- yo1 (* 0.5 gap))))
          ; distance for mirroring in Y relative to the lower edges
          (extra-gap (- (+ ymin yo1)))
          ; transformation chain ...
          (stil-3 (ly:stencil-rotate-absolute colored-stil 45.0 0.0 0.0))
          (stil-4 (ly:stencil-scale stil-3 px py))
          (stil-5 (ly:stencil-outline (ly:stencil-rotate-absolute stil-4 (- -45.0 half-ang) 0.0 0.0)
                                      (make-filled-box-stencil (cons xmin xmax) (cons ymin ymax))))
          (stil-with-mirror (ly:stencil-add
                            (ly:stencil-translate
                              (ly:stencil-scale stil-5 1 -1)
                            (cons (- x-low-dist)              ; to align the lower left edge with its sheared transformation
                                  (* -1 (+ gap extra-gap))))  ; extra-gap corrects the origin in Y direction
                            stil))
        )
    ;      (write-me "180/PI " (/ PI 180))
    stil-with-mirror
  ))
 
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

hello = \markup
% \overlay {
    \override #'(box-padding . 0.0) \with-color #darkgreen \box
    \with-color #black \fontsize #6 "Hello world!"
%  \with-color #magenta \path #0.2 #'((moveto 2 1) (lineto 0 0) (lineto 1 2))
% }

hellox = \markup
% \overlay {
    \override #'(box-padding . 0.0) \with-color #darkgreen \box
    \score {
      \relative { c'4 d e f g2 a8 g f16 e }
      \layout {
        ragged-right = ##t
        line-width = #60
        \context {
          \Score
          \override NonMusicalPaperColumn.line-break-permission = ##f
          \override SpacingSpanner.common-shortest-duration = #(ly:make-moment 1/1)
        }
      }
    }
%  \with-color #magenta \path #0.2 #'((moveto 2 1) (lineto 0 0) (lineto 1 2))
% }

%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\markup \line {
  \left-column {
    \hello
  }
  \left-column {
    \mirror \hello #45 #(x11-color 'LightCoral) #1
  }
  \left-column {
    \mirror \hello #45 #(x11-color 'MediumSpringGreen) #2
  }
}

%{
\markup \line {
  \left-column {
    \mirror \hellox #45 #(x11-color 'LightCoral) #1
  }
  \left-column {
    \mirror \hellox #45 #(x11-color 'MediumSpringGreen) #2
  }
}

\markup \line {
  \left-column {
    \hello
  }
  \left-column {
    \mirror \hello #-70 #(x11-color 'LightCoral) #1
  }
  \left-column {
    \mirror \hello #-30 #(x11-color 'MediumSpringGreen) #2
  }
}
%}

\markup \line {
  \left-column {
    \mirror \hellox #-70 #(x11-color 'DarkSlateGrey) #1    % no longer a large gap requested
  }
  \left-column {
    \mirror \hellox #-30 #(x11-color 'MediumAquamarine) #2  % no longer a large gap requested
  }
}

Arnold.
Titel: Antw:Markup geschert spiegeln funktioniert nicht (ganz) bei Score-Markup
Beitrag von: Manuela am Donnerstag, 20. April 2023, 21:10
Danke für die Hinweise, Arnold. Anhand deines anderen Codes habe ich so etwas schon vermutet.