Find the tangent of a point on a cubic bezier curve

bezier curve equation
bezier curve fitting
bezier curve through points
how to find control points of bezier curve
derivative of bézier curve
bezier curve example
rational bézier curve
algorithm for bezier curve

For a cubic Bézier curve, with the usual four points a, b, c and d,

for a given value t,

how to most elegantly find the tangent at that point?

The tangent of a curve is simply its derivative. The parametric equation that Michal uses:

P(t) = (1 - t)^3 * P0 + 3t(1-t)^2 * P1 + 3t^2 (1-t) * P2 + t^3 * P3

should have a derivative of

dP(t) / dt =  -3(1-t)^2 * P0 + 3(1-t)^2 * P1 - 6t(1-t) * P1 - 3t^2 * P2 + 6t(1-t) * P2 + 3t^2 * P3 

Which, by the way, appears to be wrong in your earlier question. I believe you're using the slope for a quadratic Bezier curve there, not cubic.

From there, it should be trivial to implement a C function that performs this calculation, like Michal has already provided for the curve itself.

Tangent to a Bezier Cubic Curve, I know the coordinates of the four points of the curve and the coordinates of the point A. See my graphic : Tangent to Bezier Cubic Curve. share. Share a link to  The tangent of a curve is simply its derivative. The parametric equation that Michal uses: P(t) = (1 - t)^3 * P0 + 3t(1-t)^2 * P1 + 3t^2 (1-t) * P2 + t^3 * P3. should have a derivative of. dP(t) / dt = -3(1-t)^2 * P0 + 3(1-t)^2 * P1 - 6t(1-t) * P1 - 3t^2 * P2 + 6t(1-t) * P2 + 3t^2 * P3.

Here is fully tested code to copy and paste:

It draws approxidistant points along the curve, and it draws the tangents.

bezierInterpolation finds the points

bezierTangent finds the tangents

There are TWO VERSIONS of bezierInterpolation supplied below:

bezierInterpolation works perfectly.

altBezierInterpolation is exactly the same, BUT it is written in an expanded, clear, explanatory manner. It makes the arithmetic much easier to understand.

Use either of those two routines: the results are identical.

In both cases, use bezierTangent to find the tangents. (Note: Michal's fabulous code base here.)

A full example of how to use with drawRect: is also included.

// MBBezierView.m    original BY MICHAL stackoverflow #4058979

#import "MBBezierView.h"



CGFloat bezierInterpolation(
    CGFloat t, CGFloat a, CGFloat b, CGFloat c, CGFloat d) {
// see also below for another way to do this, that follows the 'coefficients'
// idea, and is a little clearer
    CGFloat t2 = t * t;
    CGFloat t3 = t2 * t;
    return a + (-a * 3 + t * (3 * a - a * t)) * t
    + (3 * b + t * (-6 * b + b * 3 * t)) * t
    + (c * 3 - c * 3 * t) * t2
    + d * t3;
}

CGFloat altBezierInterpolation(
   CGFloat t, CGFloat a, CGFloat b, CGFloat c, CGFloat d)
    {
// here's an alternative to Michal's bezierInterpolation above.
// the result is absolutely identical.
// of course, you could calculate the four 'coefficients' only once for
// both this and the slope calculation, if desired.
    CGFloat C1 = ( d - (3.0 * c) + (3.0 * b) - a );
    CGFloat C2 = ( (3.0 * c) - (6.0 * b) + (3.0 * a) );
    CGFloat C3 = ( (3.0 * b) - (3.0 * a) );
    CGFloat C4 = ( a );

    // it's now easy to calculate the point, using those coefficients:
    return ( C1*t*t*t + C2*t*t + C3*t + C4  );
    }







CGFloat bezierTangent(CGFloat t, CGFloat a, CGFloat b, CGFloat c, CGFloat d)
 {
    // note that abcd are aka x0 x1 x2 x3

/*  the four coefficients ..
    A = x3 - 3 * x2 + 3 * x1 - x0
    B = 3 * x2 - 6 * x1 + 3 * x0
    C = 3 * x1 - 3 * x0
    D = x0

    and then...
    Vx = 3At2 + 2Bt + C         */

    // first calcuate what are usually know as the coeffients,
    // they are trivial based on the four control points:

    CGFloat C1 = ( d - (3.0 * c) + (3.0 * b) - a );
    CGFloat C2 = ( (3.0 * c) - (6.0 * b) + (3.0 * a) );
    CGFloat C3 = ( (3.0 * b) - (3.0 * a) );
    CGFloat C4 = ( a );  // (not needed for this calculation)

    // finally it is easy to calculate the slope element,
    // using those coefficients:

    return ( ( 3.0 * C1 * t* t ) + ( 2.0 * C2 * t ) + C3 );

    // note that this routine works for both the x and y side;
    // simply run this routine twice, once for x once for y
    // note that there are sometimes said to be 8 (not 4) coefficients,
    // these are simply the four for x and four for y,
    // calculated as above in each case.
 }







@implementation MBBezierView

- (void)drawRect:(CGRect)rect {
    CGPoint p1, p2, p3, p4;

    p1 = CGPointMake(30, rect.size.height * 0.33);
    p2 = CGPointMake(CGRectGetMidX(rect), CGRectGetMinY(rect));
    p3 = CGPointMake(CGRectGetMidX(rect), CGRectGetMaxY(rect));
    p4 = CGPointMake(-30 + CGRectGetMaxX(rect), rect.size.height * 0.66);

    [[UIColor blackColor] set];
    [[UIBezierPath bezierPathWithRect:rect] fill];
    [[UIColor redColor] setStroke];
    UIBezierPath *bezierPath = [[[UIBezierPath alloc] init] autorelease];   
    [bezierPath moveToPoint:p1];
    [bezierPath addCurveToPoint:p4 controlPoint1:p2 controlPoint2:p3];
    [bezierPath stroke];

    [[UIColor brownColor] setStroke];

 // now mark in points along the bezier!

    for (CGFloat t = 0.0; t <= 1.00001; t += 0.05) {
  [[UIColor brownColor] setStroke];

        CGPoint point = CGPointMake(
            bezierInterpolation(t, p1.x, p2.x, p3.x, p4.x),
            bezierInterpolation(t, p1.y, p2.y, p3.y, p4.y));

            // there, use either bezierInterpolation or altBezierInterpolation,
            // identical results for the position

        // just draw that point to indicate it...
        UIBezierPath *pointPath =
           [UIBezierPath bezierPathWithArcCenter:point
             radius:5 startAngle:0 endAngle:2*M_PI clockwise:YES];
        [pointPath stroke];

        // now find the tangent if someone on stackoverflow knows how
        CGPoint vel = CGPointMake(
            bezierTangent(t, p1.x, p2.x, p3.x, p4.x),
            bezierTangent(t, p1.y, p2.y, p3.y, p4.y));

        // the following code simply draws an indication of the tangent
        CGPoint demo = CGPointMake( point.x + (vel.x*0.3),
                                      point.y + (vel.y*0.33) );
        // (the only reason for the .3 is to make the pointers shorter)
        [[UIColor whiteColor] setStroke];
        UIBezierPath *vp = [UIBezierPath bezierPath];
        [vp moveToPoint:point];
        [vp addLineToPoint:demo];
        [vp stroke];
    }   
}

@end

to draw that class...
MBBezierView *mm = [[MBBezierView alloc]
                     initWithFrame:CGRectMake(400,20, 600,700)];
[mm setNeedsDisplay];
[self addSubview:mm];

Here are the two routines to calculate approximately equidistant points, and the tangents of those, along a bezier cubic.

For clarity and reliability, these routines are written in the simplest, most explanatory, way possible.

CGFloat bezierPoint(CGFloat t, CGFloat a, CGFloat b, CGFloat c, CGFloat d)
    {
    CGFloat C1 = ( d - (3.0 * c) + (3.0 * b) - a );
    CGFloat C2 = ( (3.0 * c) - (6.0 * b) + (3.0 * a) );
    CGFloat C3 = ( (3.0 * b) - (3.0 * a) );
    CGFloat C4 = ( a );

    return ( C1*t*t*t + C2*t*t + C3*t + C4  );
    }

CGFloat bezierTangent(CGFloat t, CGFloat a, CGFloat b, CGFloat c, CGFloat d)
    {
    CGFloat C1 = ( d - (3.0 * c) + (3.0 * b) - a );
    CGFloat C2 = ( (3.0 * c) - (6.0 * b) + (3.0 * a) );
    CGFloat C3 = ( (3.0 * b) - (3.0 * a) );
    CGFloat C4 = ( a );

    return ( ( 3.0 * C1 * t* t ) + ( 2.0 * C2 * t ) + C3 );
    }

The four precalculated values, C1 C2 C3 C4, are sometimes called the coefficients of the bezier. (Recall that a b c d are usually called the four control points.)

Of course, t runs from 0 to 1, for example every 0.05.

Simply call these routines once for X, and then once separately for Y.

Hope it helps someone!


Important facts:

(1) It is an absolute fact that: unfortunately, there is, definitely, NO method, provided by Apple, to extract points from a UIBezierPath. True as of 2019.

(2) Don't forget it's as easy as pie to animate something along a UIBezierPath. Google many examples.

(3) Many ask, "Can't CGPathApply be used to extract the points from a UIBezierPath?" No, CGPathApply is totally unrelated: it simply gives you a list of your "instructions in making any path" (so, "start here", "draw a straight line to this point", etc etc.) The name is confusing but CGPathApply is totally unrelated to bezier paths.


For game programmers - as @Engineer points out you may well want the normal of the tangent, fortunately Apple has vector math built-in:

https://developer.apple.com/documentation/accelerate/simd/working_with_vectors https://developer.apple.com/documentation/simd/2896658-simd_normalize

Derivatives of a Bézier Curve, The right figure shows two Bézier curves that are tangent to a line at the joining point. However, they are not C1 continuous. The left curve is of degree 4, while the  I need to draw a tangent, normal and binormal at each of the Bezier points. As far as I know, to find a tangent at any given value of t, the equation is P'(t) = 4 * (1-t)^3 *(P1 - P0) + 12 *(1-t)^2*t*(P2-P1) + 12 * (1-t) * t^2 * (P3-P2) + 4 * t^3 * (P4-P3)

I found it too error-prone to use the supplied equations. Too easy to miss a subtle t or misplaced bracket.

By contrast, Wikipedia provides a much clearer, cleaner, derivative IMHO:

...which implements easily in code as:

3f * oneMinusT * oneMinusT * (p1 - p0)
+ 6f * t * oneMinusT * (p2 - p1)
+ 3f * t * t * (p3 - p2)

(assuming you have vector-minus configured in your language of choice; question isn't marked as ObjC specifically, and iOS now has several langs available)

Cubic Bezier Curve Tangent - Math and Physics, I'm trying to compute the tangent of a Cubic bezier curve, to get the + 3*P2*t^2​*(1-t) + P3*t^3 Where P0 to P3 are my four control point. I have a quadratic bezier curve and I want to calculate the slope of the tangent in a given point. For example, let it be the middlepoint of the quadratic bezier curve, therefore t=0.5 (please see the link below for a picture of this).

I couldn't get any of this to work until I realized that for parametric equations, (dy/dt)/(dx/dt) = dy/dx

Bezier Curve Derivation, A Bezier curve is defined on four points as shown below: first data point and 1/​3 behind the second data point, respectively, but on the same tangent line as the Hermite control points. So we get the Bezier matrix: De Casteljau developed an alternative method of constructing a cubic Bezier curve, based on geometry. Let us define our cubic bezier curve mathematically. So a bezier curve id defined by a set of control points to where n is called its order(n = 1 for linear , n = 2 for quadratic , etc.). The first and last control points are always the end points of the curve; however, the intermediate control points (if any) generally do not lie on the curve.

Here goes my Swift implementation.

Which I tried my best to optimize for speed, by eliminating all redundant math operations. i.e. make the minimal numbers of calls to math operations. And use the least possible number of multiplications (which are much more expensive than sums).

There are 0 multiplications to create the bezier. Then 3 multiplications to get a point of bezier. And 2 multiplications to get a tangent to the bezier.

struct CubicBezier {

    private typealias Me = CubicBezier
    typealias Vector = CGVector
    typealias Point = CGPoint
    typealias Num = CGFloat
    typealias Coeficients = (C: Num, S: Num, M: Num, L: Num)

    let xCoeficients: Coeficients
    let yCoeficients: Coeficients

    static func coeficientsOfCurve(from c0: Num, through c1: Num, andThrough c2: Num, to c3: Num) -> Coeficients
    {
        let _3c0 = c0 + c0 + c0
        let _3c1 = c1 + c1 + c1
        let _3c2 = c2 + c2 + c2
        let _6c1 = _3c1 + _3c1

        let C = c3 - _3c2 + _3c1 - c0
        let S = _3c2 - _6c1 + _3c0
        let M = _3c1 - _3c0
        let L = c0

        return (C, S, M, L)
    }

    static func xOrYofCurveWith(coeficients coefs: Coeficients, at t: Num) -> Num
    {
        let (C, S, M, L) = coefs
        return ((C * t + S) * t + M) * t + L
    }

    static func xOrYofTangentToCurveWith(coeficients coefs: Coeficients, at t: Num) -> Num
    {
        let (C, S, M, _) = coefs
        return ((C + C + C) * t + S + S) * t + M
    }

    init(from start: Point, through c1: Point, andThrough c2: Point, to end: Point)
    {
        xCoeficients = Me.coeficientsOfCurve(from: start.x, through: c1.x, andThrough: c2.x, to: end.x)
        yCoeficients = Me.coeficientsOfCurve(from: start.y, through: c1.y, andThrough: c2.y, to: end.y)
    }

    func x(at t: Num) -> Num {
        return Me.xOrYofCurveWith(coeficients: xCoeficients, at: t)
    }

    func y(at t: Num) -> Num {
        return Me.xOrYofCurveWith(coeficients: yCoeficients, at: t)
    }

    func dx(at t: Num) -> Num {
        return Me.xOrYofTangentToCurveWith(coeficients: xCoeficients, at: t)
    }

    func dy(at t: Num) -> Num {
        return Me.xOrYofTangentToCurveWith(coeficients: yCoeficients, at: t)
    }

    func point(at t: Num) -> Point {
        return .init(x: x(at: t), y: y(at: t))
    }

    func tangent(at t: Num) -> Vector {
        return .init(dx: dx(at: t), dy: dy(at: t))
    }
}

Use like:

let bezier = CubicBezier.init(from: .zero, through: .zero, andThrough: .zero, to: .zero)

let point02 = bezier.point(at: 0.2)
let point07 = bezier.point(at: 0.7)

let tangent01 = bezier.tangent(at: 0.1)
let tangent05 = bezier.tangent(at: 0.5)

[PDF] Math 149 W02 BB. Cubic B éeziercurves 1. Overview B éezier , It does not matter which end you consider to be the first and which the last; you get the same points for the curve either way. Observe that the curve is tangent to​  Exam Question solved: Factorise Cubic, given repeated root, to find coordinates of point where tangent meets curve again: Edexcel Jan 09 C4 Question 7c.

[PDF] Bezier Curves, Bezier Curves. AML710 CAD Conversion to Cubic A Bezier Curve is obtained by a defining polygon. tangent between the first two points and the last two points Substituting these values for the tangent vectors we get the equivalent. Derivatives of a Bézier Curve . To compute tangent and normal vectors at a point on a Bézier curve, we must compute the first and second derivatives at that point. Fortunately, computing the derivatives at a point on a Bézier curve is easy. Recall that the Bézier curve defined by n + 1 control points P 0, P 1, , P n has the following

Parametric Equations: Solve Cubic to find where Tangent intersects , What are the bounding boxes, how do you determine intersections, how can you extrude a Playing with the points for curves may have given you a feel for how Bézier different functions (one uses a sine, the other a cosine); but Bézier curves use the for quadratic and cubic curves, with "S" being the strength of a point's  At the end point, the curve is always tangent to, and in the same direction as, a straight line from the second control point to the end point. The cubic Bézier curve is always bounded by a convex quadrilateral connecting the four points. This is called a convex hull.

A Primer on Bézier Curves, For a cubic Bézier curve, with the usual four points a, b, c and d,. for a given value t,. how to most elegantly find the tangent at that point? Transition timing functions defined by bezier curves. Cubic bezier curves are one of two ways of expressing timing functions in CSS (steps() being the other). The cubic-bezier(x1, y1, x2, y2) notation for CSS timing functions specifies the coordinates of \( P_1 \) and \( P_2 \) of a cubic bezier curve.

Comments
  • Hugely useful, thanks. Note that you should be normalising the tangent once you have calculated it, as the function provides a vector of arbitrary length - actually it grows as t grows. This should help others to do that.
  • @Engineer thanks, indeed in many cases you would want to normalize the tangent - and good news, there're actually built-in functions for normalize and other vector math! developer.apple.com/documentation/simd/2896658-simd_normalize
  • Hah, not even using this for Apple related development, and used to writing my own vector code - a good general purpose answer regardless of language / platform.
  • Perfect, but anything this long just breaks in current Swift, unfortunately
  • I improved the algorithm even more meanwhile, by making sure the compiler won't create multiplications where there is no real need for them to exist. Enjoy.