Markup geschert spiegeln funktioniert nicht (ganz) bei Score-Markup

Begonnen von Manuela, Samstag, 8. April 2023, 13:44

« vorheriges - nächstes »

Manuela

Ich habe den Code aus diesem Thread 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
  }
}
Danke für eure Hilfe
viele Grüße
-- Manuela

Arnold

#1
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.

Arnold

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.

Manuela

Danke für die Hinweise, Arnold. Anhand deines anderen Codes habe ich so etwas schon vermutet.
Danke für eure Hilfe
viele Grüße
-- Manuela