Am 19.09.2016 um 00:32 schrieb David Kastrup: > Urs Liska <u...@openlilylib.org> writes: > >> Am 18.09.2016 um 20:54 schrieb David Kastrup: >>> Do you know how to split a bezier at a given ratio into equivalent >>> beziers? It's a comparatively simple operation and I think it's already >>> somewhere in the C++ code though without access from Scheme. >> No, but I should be able to figure it out (if noone sends a pointer >> before I manage to do so). > Well, METAFONT uses the notation > > a[z1, z2] > > for z1 + a*[z2-z1], mapping a range of 0..1 for a linearly between z1 > and z2. > > If we have points z1, z2, z3, z4 defining a Bezier, then the two split > beziers are defined with the points > > z1, a[z1, z2], a[a[z1, z2], a[z2, z3]], a[a[a[z1, z2], a[z2, z3]], > a[a[z2, z3], a[z3, z4]] > > and > > a[a[a[z1, z2], a[z2, z3]], a[a[z2, z3], a[z3, z4]]], > a[a[z2, z3], a[z3, z4]], a[z3, z4], z4 > > Basically, calculation of a point a on an n-grade Bezier is done using a > recursive formula to depth n, and keeping the intermediate results will > give you the control points for the Bezier curves split at that point. >
I think before diving into that I share what I currently have, so we may discuss which approach should actually be continued. The attached solution does the following: * Apply offsets for the start/end points and to the second and second-to-last control-points, based on the original points of the non-compound slur * Add an inflection point, which is specified as a point between the (actual) end points of the slur, given X and Y ratios (as a pair of numbers between 0 and 1 * Determine the length and slope of the line going through the inflection point. o Currently this is done through specifying one point relative to the inflection point and mirroring it symmetrically o Instead I'd like to specify an angle and a length. o It would be nice to have the angle relative to the slope of the slur as a whole, but that may not be a good idea, as we have actually two separate lines with different slopes o Length should be given as a ratio, presumable relative to the length of the line between the inflection point and the respective end point. o There should be one optional argument to enforce symmetrical points here. BTW I've spiced up the control points display a bit. I hope it's self-explanatory. I would like to integrate this with Janek's \shapeII functions (https://github.com/openlilylib/snippets/tree/master/notation-snippets/shaping-bezier-curves) as I think there'll be quite some code (and interface?) that can be shared. Opinions? Urs
%%%%%%%%%%%%%%%%%%%%%%%% \version "2.19.47" \language "deutsch" #(define (make-cross-stencil coord col) "Draw a cross-stencil at coord." (let ((thick 0.1) (sz 0.2)) (stencil-with-color (ly:stencil-add (make-line-stencil thick (- (car coord) sz) (- (cdr coord) sz) (+ (car coord) sz) (+ (cdr coord) sz)) (make-line-stencil thick (- (car coord) sz) (+ (cdr coord) sz) (+ (car coord) sz) (- (cdr coord) sz))) col) )) #(define (connect-dots pt1 pt2 col) (stencil-with-color (ly:stencil-add (make-line-stencil 0.05 (car pt1) (cdr pt1) (car pt2) (cdr pt2))) col)) #(define (mirror-point pt1 pt2) "Mirror pt2 against pt1" (cons (- (* 2 (car pt1)) (car pt2)) (- (* 2 (cdr pt1)) (cdr pt2)))) #(define (add-points pt1 pt2) "Add two points" (cons (+ (car pt1) (car pt2)) (+ (cdr pt1) (cdr pt2)))) #(define (divide pt1 pt2 ratio) "" (let* ((x1 (car pt1)) (x2 (car pt2)) (y1 (cdr pt1)) (y2 (cdr pt2)) (xratio (car ratio)) (yratio (cdr ratio)) (newcenter (cons (+ (* (- 1 xratio) x1) (* xratio x2)) (+ (* (- 1 yratio) y1) (* yratio y2))))) (display newcenter) newcenter)) #(define (distance pt1 pt2) (let ((square (lambda (x) (* x x)))) (sqrt (+ (square (- (car pt1) (car pt2))) (square (- (cdr pt1) (cdr pt2))))))) compoundSlur = #(define-event-function (options)(ly:context-mod?) ; TODO: Change inner-segment to ; - a ratio (to the length of the line between cp1 and cp4) ; - an angle (relative to the same line cp1--cp2) (let ((proc (lambda (grob) (let* ((opts (map (lambda (o) (cons (second o) (third o))) (ly:get-context-mods options))) ; TODO: factor out requiring/defaulting options ;; let offsets default to taking the control-points of the automatic slur (offsets (let ((prop (assq 'offsets opts))) (if prop (cdr prop) '((0 . 0)(0 . 0)(0 . 0)(0 . 0))))) ;; let center-ratio default to 0.5/0.5 (center-ratio (let ((prop (assq 'center-ratio opts))) (if prop (cdr prop) '(.5 . .5)))) (inner-ratio (let ((prop (assq 'center-ratio opts))) (if prop (cdr prop) 0.5))) (inner-segment (assq-ref opts 'inner-segment)) (ann? (let ((prop (assq 'ann opts))) (if prop (cdr prop) #f))) ;; automatic control points of the non-compound slur (cps (ly:slur::calc-control-points grob)) ;; add offsets to the four control points (cp1 (add-points (first cps) (first offsets))) (cp2 (add-points (second cps) (second offsets))) (cp6 (add-points (third cps) (third offsets))) (cp7 (add-points (fourth cps) (fourth offsets))) ;; calculate central connecting point and surrounding handles (cp4 (divide cp1 cp7 center-ratio)) (inner-len (distance cp1 cp7)) (slope (/ (- (cdr cp7) (cdr cp1)) (- (car cp7) (car cp1)))) (cp5 (add-points cp4 inner-segment)) (cp3 (mirror-point cp4 cp5)) (cps1 (list cp1 cp2 cp3 cp4)) (cps2 (list cp4 cp5 cp6 cp7)) (first-spline-stil (begin (ly:grob-set-property! grob 'control-points cps1) (ly:slur::print grob))) (second-spline-stil (begin (ly:grob-set-property! grob 'control-points cps2) (ly:slur::print grob))) ;; annotates all new control-points (crosses (if ann? (apply ly:stencil-add (append ;; display control points of the original, non-compound slur (map (lambda (c) (make-cross-stencil c cyan)) cps) ;; display actual control points of the compound slur (map (lambda (c) (make-cross-stencil c red)) (append cps1 cps2)) ;; display connections between original and offset control points (map (lambda (c1 c2) (connect-dots c1 c2 cyan)) cps (list cp1 cp2 cp6 cp7)) ;; display handles indicating the (map (lambda (c1 c2) (connect-dots c1 c2 red)) (list cp1 cp3 cp4 cp7) (list cp2 cp4 cp5 cp6)) )) empty-stencil)) ) (ly:message "angle: ~a" slope) (ly:stencil-add first-spline-stil second-spline-stil crosses ))))) #{ -\tweak stencil $proc ( #})) upper = \relative { \key d \major \clef bass s2 r8 d,16 g h d g h d8 r s2. s4 \voiceTwo h8.(-- c16-- h2--) } lower = \relative { \key d \major \clef bass r2 <d' h g=>~-^ % Uncomment one out of the following lines to compare the % default slur with the compound one %( %%{ -\compoundSlur \with { offsets = % offsets against the automatic control points % of the original, non-compound slur #'((0 . -1.5) ; left starting point (-2 . -1) ; second control point (-2 . 1) ; second-to-last control point (0 . 0)) % right end point center-ratio = #'(0.6 . 0.65) % X/Y ratio of the inflection point % calculated between the actual end points of the slur % TODO: change to ratio and angle props (then create defaults) inner-segment = #'(4 . 6) % X/Y of the (so far symmetric) line around the % inflection point ann = ##t % Display control points } %} << { <d h g>4 % Uncomment one of the following lines to see the robustness of the slur <c g e>4 % <c g e>16 q q q <h g>4 \voiceOne cis \change Staff = upper \clef treble \voiceOne d e fis2 ) \fermata } \new Voice { \voiceTwo s2. <g,= e>4 \oneVoice <fis h,> <g e> <fis dis>2\fermata } >> } \score { << \new PianoStaff << \new Staff = upper \upper \new Staff = lower \lower >> >> } %%%%%%%%%%%%%%%%%%%%%%%
compound-slur-relative.preview.pdf
Description: Adobe PDF document
_______________________________________________ lilypond-user mailing list lilypond-user@gnu.org https://lists.gnu.org/mailman/listinfo/lilypond-user