Re: Re[2]: Slur with left and/or right arrow head

2019-04-20 Thread Thomas Morley
Am Fr., 19. Apr. 2019 um 23:37 Uhr schrieb Trevor :
>
>
> Aaron, Harm
>
> Could I please comment on just one feature? The overrides to add or inhibit 
> arrow-heads at the left and right ends of the Slur are:
>
>   \override Slur.details.arrow-left = #LEFT
>   \override Slur.details.arrow-right = #RIGHT
>   \override Slur.details.arrow-left = ##f
>   \override Slur.details.arrow-right = ##f
>
> This slightly confused me, especially when I tried
>
>   \override Slur.details.arrow-right = #LEFT
>
> which draws a left-pointing arrow-head at the right end of the Slur. 
> Something I don't think anyone would want.
>
> Why not have the simpler and less confusing
>
>   \override Slur.details.arrow-left = ##t
>   \override Slur.details.arrow-right = ##t
>   \override Slur.details.arrow-left = ##f
>   \override Slur.details.arrow-right = ##f
>
> ?
>
> Trevor

Hi Trevor,

yep, it's the same concern Lukas already raised.

Attached the next iteration of the code.
arrow-left/right will now operate on the boolean #f or any not-false value.
If the not-false value is a procedure, it will be evaluated.
This is needed to make alterBroken etc work (some commented examples
in \layout).
Regrettable this has some negative impact on the performance. Not sure
whether this can be improved.
If the not-false value is something else, it's taken as #t.

Cheers,
  Harm
\version "2.19.82"

%% Thanks to Aaron Hill
%% http://lists.gnu.org/archive/html/lilypond-user/2019-04/msg00240.html 

%% Does not work for 2.18.2 because of
%%   - grob::name (could be replaced by grob-name, see p.e. LSR)
%%   - minimum-length-after-break (no direct replacement possible, only used in
%% the examples, though)
  
#(ly:load "bezier-tools.scm")

#(define (note-column-bounded? dir grob)
"Checks wether @var{grob} is a spanner and whether the spanner is bounded in
@var{dir}-direction by a note-column."
  (if (ly:spanner? grob)
  (grob::has-interface (ly:spanner-bound grob dir) 'note-column-interface)
  #f))

#(define (offset-number-pair-list l1 l2)
"Offset the number-pairs of @var{l1} by the matching number-pairs of @var{l2}"
;; NB no type-checking or checking for equal lengths is done here
  (map (lambda (p1 p2) (offset-add p1 p2)) l1 l2))

#(define (bezier::point control-points t)
"Given a Bezier curve of arbitrary degree specified by @var{control-points},
compute the point at the specified position @var{t}."
  (if (< 1 (length control-points))
  (let ((q0 (bezier::point (drop-right control-points 1) t))
(q1 (bezier::point (drop control-points 1) t)))
(cons
  (+ (* (car q0) (- 1 t)) (* (car q1) t))
  (+ (* (cdr q0) (- 1 t)) (* (cdr q1) t
  (car control-points)))

#(define (bezier::angle control-points t)
"Given a Bezier curve of arbitrary degree specified by @var{control-points},
compute the slope at the specified position @var{t}."
  (let ((q0 (bezier::point (drop-right control-points 1) t))
(q1 (bezier::point (drop control-points 1) t)))
(ly:angle (- (car q1) (car q0)) (- (cdr q1) (cdr q0)

#(define* 
  (bezier::approx-control-points-to-length 
control-points dir length 
#:optional (precision 0.01) (right-t 0.2) (left-t 0.8))
"Given a Bezier curve specified by @var{control-points}, return 
new control-points where the length of the Bezier specified by them is approx
@var{length}.
The procedure returns if difference of the new calculated length and the given
@var{length} is lower than optional @var{precision}.
The optional @var{left-t} and @var{right-t} represent the steps where new
control-points are calculated relying on @var{dir}."
  ;; TODO
  ;; Do the values for precision, left-t, right-t cover all cases?
  (let*  ((frst-cp (car control-points))
  (last-cp (last control-points))
  (actual-length
(ly:length 
  (- (car frst-cp) (car last-cp))
  (- (cdr frst-cp) (cdr last-cp
  (diff (- (abs actual-length) (abs length
  (if (< diff precision)
  control-points
  (bezier::approx-control-points-to-length
(if (positive? dir)
(cdr (split-bezier control-points right-t))
(car (split-bezier control-points left-t)))
dir
length

#(define (bezier::adjusted-arrow-head dir control-points)
(lambda (curve)
"Returns a stencil build from an arrowhead-glyph, adjusted to fit at start/end
of a curve looking at the curve's @var{control-points}.
Relying on @var{dir} for looking at left or right side of the curve."
  (if (not dir)
  empty-stencil
  (let* ((staff-space (ly:staff-symbol-staff-space curve))
 ;; reducing fs-from-staff-space a bit looks nicer
 (fs-from-staff-space (1- (magnification->font-size staff-space)))
 (grob-font
   (ly:paper-get-font
 (ly:grob-layout curve)
 `(((font-encoding . fetaMusic)
(font-size . 

Re[2]: Slur with left and/or right arrow head

2019-04-19 Thread Trevor


Aaron, Harm

Could I please comment on just one feature? The overrides to add or 
inhibit arrow-heads at the left and right ends of the Slur are:


  \override Slur.details.arrow-left = #LEFT
  \override Slur.details.arrow-right = #RIGHT
  \override Slur.details.arrow-left = ##f
  \override Slur.details.arrow-right = ##f

This slightly confused me, especially when I tried

  \override Slur.details.arrow-right = #LEFT

which draws a left-pointing arrow-head at the right end of the Slur. 
Something I don't think anyone would want.


Why not have the simpler and less confusing

  \override Slur.details.arrow-left = ##t
  \override Slur.details.arrow-right = ##t
  \override Slur.details.arrow-left = ##f
  \override Slur.details.arrow-right = ##f

?

Trevor

-- Original Message --
From: "Thomas Morley" 
To: "Aaron Hill" ; "Lukas-Fabian Moser" 


Cc: "lilypond-user" 
Sent: 19/04/2019 22:03:31
Subject: Re: Slur with left and/or right arrow head


Am Di., 16. Apr. 2019 um 23:45 Uhr schrieb Aaron Hill
:


 On 2019-04-16 10:37 am, Thomas Morley wrote:
 > Am Mo., 15. Apr. 2019 um 19:26 Uhr schrieb Lukas-Fabian Moser
 > :
 >>
 >> Folks,
 >>
 >> in
 >> https://archiv.lilypondforum.de/index.php?topic=1744.msg9669#msg9669,
 >> Harm invented a truly wonderful new feature allowing to add an arrow
 >> head to the right end of a Slur (or, for that matter, a Tie,
 >> PhrasingSlur etc.). I reproduce it here with only trivial changes
 >> (mainly omitting parser/location).
 >>
 >> Now I also need slurs with arrows pointing to the left (and ideally,
 >> also the option to have an arrow tip at both ends of the Slur). At
 >> first
 >> glance the asymmetry favoring the right hand side of a Slur seems to
 >> be
 >> hard-coded pretty deeply in Harm's code. Is there a cheap way to add a
 >> choice of "left or right end" (if not even the "or/and" possibility)?
 >>
 >> Best
 >> Lukas
 >
 > Hi Lukas,
 >
 > I started to implement the functionality, finally I more or less
 > rewrote anything.
 > As David K once said: rewriting all means at least knowing where the
 > bugs are...

 Harm,

 There is an annoying optical issue where using the angle of the curve at
 the end points does not work well for an arrow head that partially
 overlaps the curve.  Instead, one needs to consider the slope of the
 curve a little inwards from the ends so that the arrow appears to be
 aligned properly.

 I took a stab at patching your code to address this.  This involved some
 additional computational work for various metrics of a Bezier curve.
 See the attached files.

 Among the things I changed is that the code that adds the arrows to the
 ends of the curve no longer applies an offset.  This offset was strictly
 horizontal which did not work well for more heavily rotated arrows.
 Instead, the offset is done within the code that computes and rotates
 the arrow, so that the center of rotation is properly defined.


Hi Aaron,

meanwhile I think I understand more about Beziers, many thanks for
your and David's explanations.
Also, I looked entirely through your code and probably understood how
you do things.

As already said I stumbled across some procedures being called over
and over, also I asked myself why we need the entire length of the
Bezier, if we are interested only in a short part at start/end.
So I wrote a procedure (relying on `split-bezierĀ“ from
bezier-tools.scm), where the Bezier is splitted, i.e. two sets of new
control-points are returned.
For those new control-points the direct line between first and last
point is calculated. If this is lower than a certain treshold, we have
control-points for a Bezier where we can calculate the angle,
otherwise it continues to recurse until the goal is reached. Relying
on start/end of the original Bezier it's first or last of the new
points, which now can serve for calculating the angle.

Function-calls are drastically reduced, performance time is reduced
and code simplified imho.

One thing I noticed are not so nice printed arrows for short Beziers
like Repeat/LaissezVibrerTie.
Likely due to the width of the arrowhead, _within_ this width the
Bezier is "too active", so to speak.


In general I've found your function to calculate a point on the Bezier
and to calculate an angle at a certain point of the Bezier _very_
helpful.
What do you think adding it to bezier-tools.scm?

Attached the newest code.

WYT?

Thanks,
  Harm

@ Lukas
Up to now I didn't tackle the arrow-left/right LEFT/RIGHT thing, I
first wanted to fight my way through the code for Beziers.
Probably tomorrow, hopefuly ...___
lilypond-user mailing list
lilypond-user@gnu.org
https://lists.gnu.org/mailman/listinfo/lilypond-user