Le 27/05/2022 à 13:28, Thomas Morley a écrit :
I decided to go for a better approximation of the bow-length, but
dropped some comments what to do, if execution time gets worse.
https://lsr.di.unimi.it/LSR/Item?u=1&id=1028
Here's an experiment:
\version "2.23.9"
#(define (bezier-curve 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-curve (drop-right control-points 1) t))
(q1 (bezier-curve (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-approx-length control-points from to steps)
"Given a Bezier curve of arbitrary degree specified by @var{control-points},
compute its approximate arc length between the positions @var{from} and
@var{to}."
(let* ((params (iota steps from (/ (- to from) (1- steps))))
(points (map (lambda (x) (bezier-curve control-points x)) params))
(length
(fold
(lambda (a b prev)
(+ prev (ly:length (- (car a) (car b)) (- (cdr a) (cdr
b)))))
0
(drop points 1)
(drop-right points 1))))
; Need to support negative length when the range is inverted.
(if (< from to) length (- length))))
#(let ((bezier '((0 . 0) (1 . 1) (2 . 1) (3 . 0))))
(for-each
(lambda (n)
(ly:message "bezier-approx-length with ~a segments: ~a"
n
(bezier-approx-length bezier 0 1 n)))
'(10 50 100 500 1000 5000 10000)))
=>
bezier-approx-length with 10 segments: 3.439011160316537
bezier-approx-length with 50 segments: 3.44323346616539
bezier-approx-length with 100 segments: 3.4433446505712593
bezier-approx-length with 500 segments: 3.4433793042010272
bezier-approx-length with 1000 segments: 3.443380369827364
bezier-approx-length with 5000 segments: 3.4433807099411706
bezier-approx-length with 10000 segments: 3.443380720552721
I don't think doing many iterations is worth it here.