(define (bezier-curve n . points) "number:0..1 #(number ...) ... -> #(number ...) get a point for a bezier curve at fractional offset n. no limit on the number of control points. no limit on the dimension of point vectors. at least one point must be given. uses the \"de casteljau\" algorithm" (if (null? (tail points)) (first points) (let ((left n) (right (- 1 n))) ; length of points is reduced by one for each recursive call (apply bezier-curve n (pair-fold-right (lambda (a result) ; ignore last point (if (null? (tail a)) result (let ((p1 (first a)) (p2 (second a))) (pair (vector-map ; map all point dimensions (lambda (p1-d p2-d) (+ (* right p1-d) (* left p2-d))) p1 p2) result)))) null points)))))
to generate the first point for example
(bezier-curve 0 (vector 0 10) (vector 10 50) (vector 5 20) (vector 8 20))
(define (cubic-bezier-curve n p1 p2 p3 p4) "number vector ... -> vector return coordinates for one point of a cubic 4-point bezier curve at fractional offset n. the intermediate points between p1 and p4 are the control points. there is no limit on the dimensions of point vectors" (let* ( (left n) (right (- 1 n)) (l-square (* left left)) (r-square (* right right)) (l-cube (* left l-square)) (r-cube (* right r-square)) (l-square (* 3 right l-square)) (r-square (* 3 left r-square))) (apply vector-map ; map all point dimensions (l (d1 d2 d3 d4) (+ (* r-cube d1) (* l-square d2) (* r-square d3) (* l-cube d4))) p1 p2 p3 p4)))
cubic_bezier_curve = (n, p1, p2, p3, p4) -> # number [number, number] ... -> [number, number] # return coordinates for one point of a cubic bezier curve at fractional offset n left = n right = 1 - left l_cube = Math.pow left, 3 r_cube = Math.pow right, 3 l_square = 3 * right * Math.pow(left, 2) r_square = 3 * left * Math.pow(right, 2) x = r_cube * p1[0] + l_square * p2[0] + r_square * p3[0] + l_cube * p4[0] y = r_cube * p1[1] + l_square * p2[1] + r_square * p3[1] + l_cube * p4[1] [x, y]
cubic_bezier_curve 0, 100, [0, 10], [10, 50], [5, 20], [8, 20]