2017-12-03

hints for programming bezier curve calculations

quadratic: one control point

cubic: two control points

alternatives: cubic hermite, centripetal catmull-rom, b-spline

links

animated-bezier interactive animations

bezierinfo explanations

bezierjs interactive examples for various bezier curve related calculations

curved-paths shows some caveats with practical usage

interpolation about interpolation methods generally

tinyspline c library for nurbs, b-splines and bezier curves

example implementations in scheme

using the "de casteljau" algorithm

(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
          (l (a result)
            ; ignore last point
            (if (null? (tail a)) result
              (let ((p1 (first a)) (p2 (second a)))
                (pair
                  (vector-map
                    ; map all point dimensions
                    (l (p1-d p2-d)
                      (+ (* right p1-d) (* left p2-d)))
                    p1 p2)
                  result))))
          null points)))))

to generate the first point

(bezier-curve 0 (vector 0 10) (vector 10 50) (vector 5 20) (vector 8 20))

optimised for only cubic bezier curves

(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)))

example implementation in coffeescript / javascript

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]

tags: programming scheme start document guide example computer bezier curve