• If there are only two control points P0 and P1, ie: N=1 then the formula reduces to a line segment between the two control points.

  • the term

  • is called a blending function since it blends the control points to form the Bézier curve.
  • The blending function is always a polynomial one degree less than the number of control points. Thus 3 control points results in a parabola, 4 control points a cubic curve etc.

  • Closed curves can be generated by making the last control point the same as the first control point. First order continuity can be achieved by ensuring the tangent between the first two points and the last two points are the same.

  • Adding multiple control points at a single position in space will add more weight to that point 'pulling' the Bézier curve towards it.

  • As the number of control points increases it is necessary to have higherorder polynomials and possibly higher factorials. It is common therefore topiece together small sections of Bézier curves to form a longer curve. Thisalso helps control local conditions, normally changing the position of onecontrol point will affect the whole curve. Of course since the curve starts andends at the first and last control point it is easy to physically match thesections. It is also possible to match the first derivative since the tangentat the ends is along the line between the two points at the end.
    Second order continuity is generally not possible.

  • Except for the redundant cases of 2 control points (straight line), it is generally not possible to derive a Bézier curve that is parallel to another Bézier curve.

  • A circle cannot be exactly represented with a Bézier curve.

  • It isn't possible to create a Bézier curve that is parallel to another, except in the trivial cases of coincident parallel curves or straight line Bézier curves.

  • Special case, 3 control points

    B(u) = P0 * ( 1 - u ) 2 + P1 * 2 * u ( 1 - u ) + P2 u2
  • Special case, 4 control points

    B(u) = P0 * ( 1 - u )3 + P1 * 3 * u * ( 1 - u )2 + P2 * 3 * u2 * ( 1 - u ) + P3 * u3
  • Bézier curves have wide applications because they are easy to compute and verystable. There are similar formulations which are also called Bézier curveswhich behave differently, in particular it is possible to create a similarcurve except that it passes through the control points. See also Spline curves. Examples

    The pink lines show the control point polygon, the grey lines theBézier curve.

    The degree of the curve is one less than the number of controlpoints, so it is a quadratic for 3 control points.It will always be symmetric for a symmetric control point arrangement.

    The curve always passes through the end points and is tangent tothe line between the last two and first two control points.This permits ready piecing of multiple Bézier curves togetherwith first order continuity.

    The curve always lies within the convex hull of the control points.Thus the curve is always 'well behaved' and does not oscillating erratically.

    Beziercode 1 268

    Closed curves are generated by specifying the first point the same as the last point. If the tangents at the first and last points matchthen the curve will be closed with first order continuity.In addition, the curve may be pulled towards a control point byspecifying it multiple times.

    C source

    Written by Paul Bourke
    March 2000

    Given four points p0, p1, p2, and p3in 3D space the cubic Bézier curve is defined as

    p(t) = a t3 + b t2 + c t + p0

    where t ranges from 0 (the start of the curve, p0) to 1 (the end of the curve, p3). The vectors a, b, c are given as follows:

    In the following examples the green markers correspond to p0and p3 of each section. The blue markers correspond top1 and p2. The grey curve is theBézier curve sampled 20 times, the samples are shown in red.The coordinates for each vertex is shown on the right.

    Example 1
    This is a single minimum piece of a piecewise Bézier curve.It is defined by 4 points, the curve passes through the two end points.The tangent at the end points is along the line to the middle two points.

    Beziercode
    0 0 1
    0.5 0 1
    1 0 0.5
    1 0 0

    Example 2
    Multiple curve pieces can be joined together to form longer continuouscurves. The curve is made continuous by the setting the tangents thesame at the join. Note that each piece of the curve is defined by tranging from 0 to 1.

    0 0 1
    0.5 0 1
    1 0 0.5
    1 0 0
    1 0 0
    1 0 -0.5
    2 0 0
    2 0 0.5

    Example 3
    By changing the tangent points between two curve pieces, sharp transitionscan be created.

    0 0 1
    0.5 0 1
    1 0 0.5
    1 0 0
    1 0 0
    1.5 0 0
    2 0 0
    2 0 0.5

    Example 4
    The 'strength' at the end points is controlled by the length of thetangent lines. The longer the line the more effect that tangent has.If the curve is being used for animation steps then the strength alsocontrols the velocity, note the samples shown in red are further apartfor the long tangent vectors.

    0 0 1
    1.75 0 1
    1 0 0.5
    1 0 0
    1 0 0
    1 0 -0.5
    2 0 -0.5
    2 0 1

    Example 5
    Straight line geometry can readily be made by aligning the tangentvectors along the line. While this may seem a frivolous use, it canbe put to good effect in animations applications. By adjusting thetangent points p1 and p2 thevelocity along the line can be controlled.


    0 0 1
    0.25 0 1
    0.75 0 1
    1 0 1
    1 0 1
    1 0 0.75
    1 0 0.25
    1 0 0
    Notes
    Source code

    FAQ

    0to p5, in order to use the Piecewise Cubic Bézierfor each section (between points pi and pi+1)one needs to find the tangent vectors shown in red.Note that for continuity between the points the tangent vector atthe end of one piece is the negative of the tangent at thestart of the next piece.

    In this first case the tangent vectors are just the differences betweensubsequent keyframe points. So for example, for the segment between p1 and p2 the four points use for the Bézierwould be p1, p2, 2p2-p3, p2. Depending on the lengthscaling for the tangent vectors, the resulting Bézier curvebetween points p1 and p3 is shown in blue. Collections 6 2 2 x 2.

    A generally better method is shown below, again one needs to find thered tangent vectors. The exact implementation will be left up to thereader but the approach I've used is to find the cross product betweenthe vectors to each neighbour, that is a vector coming outof the page (or into the page) in the diagram below. The tangentvectors (red) are found by taking the cross product of that withthe green normal vectors. The main reason for using this approachis that it overcomes a mirror symmetry problem that occurs if onesimple tries to rotate the green normal vectors +- 90 degrees.Note that the case of 3 collinear points needs to be treated as a specialcase.

    An improvement by Lars Jensen is illustrated below. It uses a normalthat bisects the two vectors to the neighbouring points along with wayof limiting the tangent lengths.

    The only remaining comment is how one deals with the first and lastpoint, normally there are some ad hoc approaches that are applicationspecific.

    Page 1 of 1
    [ 10 posts ]
    Print viewPrevious topic | Next topic
    AuthorMessage
    Posted: Fri Aug 12, 2016 11:30 am
    Enthusiast

    Joined: Fri Oct 06, 2006 3:57 pm
    Posts: 570
    Location: England
    Need some maths/charting help.
    I want to plot a smooth line through all of the data points in the chart created by the code below.
    I know it has something to do with interpolation, but I can't get my head around it ( maths is not my stroing point ) and wonder if anyone can lead me in the right direction.
    BTW this code is very rough and is just to illustrate my problem
    NewList raw_data()
    AddElement(raw_data())
    raw_data() = 00
    AddElement(raw_data())
    raw_data() = 02
    AddElement(raw_data())
    raw_data() = 08
    AddElement(raw_data())
    raw_data() = 18
    AddElement(raw_data())
    raw_data() = 32
    AddElement(raw_data())
    raw_data() = 47
    AddElement(raw_data())
    raw_data() = 63
    AddElement(raw_data())
    raw_data() = 79
    AddElement(raw_data())
    raw_data() = 91
    AddElement(raw_data())
    raw_data() = 98
    AddElement(raw_data())
    raw_data() = 99
    AddElement(raw_data())
    raw_data() = 99
    If OpenWindow(0, 0, 0, 800, 600, 'VectorDrawing', #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
    CanvasGadget(0, 0, 0, 800, 600)
    If StartVectorDrawing(CanvasVectorOutput(0))
    ; draw axis
    MovePathCursor(40, 40)
    AddPathLine(0, 520, #PB_Path_Relative)
    AddPathLine(720, 0, #PB_Path_Relative)
    VectorSourceColor(RGBA(0, 0, 0, 255))
    StrokePath(1, #PB_Path_SquareEnd )
    ; show points
    offset = 0
    ResetList(raw_data())
    ForEach raw_data()
    AddPathCircle(40 + offset, 560 - (raw_data()*3), 1)
    offset + 50
    Next
    VectorSourceColor(RGBA(255, 0, 0, 255))
    StrokePath(20, #PB_Path_SquareEnd )
    ; show bars
    offset = 0
    ResetList(raw_data())
    ForEach raw_data()
    MovePathCursor(40 + offset, 560 - (raw_data()*3))
    AddPathLine(40 + offset, 560, #PB_Path_Default)
    offset + 50
    Next
    VectorSourceColor(RGBA(0, 0, 255, 255))
    StrokePath(10, #PB_Path_SquareEnd )
    StopVectorDrawing()
    EndIf
    Repeat
    Event = WaitWindowEvent()
    Until Event = #PB_Event_CloseWindow
    EndIf


    Top

    Beziercode 1 263

    Posted: Fri Aug 12, 2016 12:08 pm
    PureBasic Expert

    Joined: Sun Aug 08, 2004 5:21 am
    Posts: 3683
    Location: Netherlands
    I want to plot a smooth line through all of the data points in the chart created by the code below.
    I know it has something to do with interpolation, but I can't get my head around it ( maths is not my stroing point ) and wonder if anyone can lead me in the right direction.

    Linear interpolation looks like connecting all the dots with line segments.
    If you want a smooth curve going through all points, you need spline interpolation.
    So the required method depends on how the result should look according to you.

    _________________
    macOS 10.15 Catalina, Windows 10


    Top
    Posted: Fri Aug 12, 2016 12:35 pm
    Addict

    Joined: Mon Oct 26, 2015 2:55 am
    Posts: 928
    Location: UA
    @spikey said right about Bezier curves.
    I've made some example with them while he posted it. Is that what you need?
    It's of course crude and has some artifacts but should show how it can be done.
    NewList raw_data()
    AddElement(raw_data())
    raw_data() = 00
    AddElement(raw_data())
    raw_data() = 02
    AddElement(raw_data())
    raw_data() = 08
    AddElement(raw_data())
    raw_data() = 18
    AddElement(raw_data())
    raw_data() = 32
    AddElement(raw_data())
    raw_data() = 47
    AddElement(raw_data())
    raw_data() = 63
    AddElement(raw_data())
    raw_data() = 79
    AddElement(raw_data())
    raw_data() = 91
    AddElement(raw_data())
    raw_data() = 98
    AddElement(raw_data())
    raw_data() = 99
    AddElement(raw_data())
    raw_data() = 99
    If OpenWindow(0, 0, 0, 800, 600, 'VectorDrawing', #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
    CanvasGadget(0, 0, 0, 800, 600)
    If StartVectorDrawing(CanvasVectorOutput(0))
    ; draw axis
    MovePathCursor(40, 40)
    AddPathLine(0, 520, #PB_Path_Relative)
    AddPathLine(720, 0, #PB_Path_Relative)
    VectorSourceColor(RGBA(0, 0, 0, 255))
    StrokePath(1, #PB_Path_SquareEnd )
    ; show points
    offset = 0
    ResetList(raw_data())
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    Global Dim BezierPoints.POINT (2), Current
    Define StartPoint.POINT
    StartPointx = 40 + offset
    StartPointy = 560
    ForEach raw_data()
    BezierPoints(Current)x = 40 + offset
    BezierPoints(Current)y = 560 - (raw_data()*3)
    AddPathCircle(40 + offset, 560 - (raw_data()*3), 1)
    offset + 50
    current + 1
    If current = 3
    MovePathCursor(StartPointx, StartPointy)
    AddPathCurve(BezierPoints(0)x, BezierPoints(0)y,
    BezierPoints(1)x, BezierPoints(1)y,
    BezierPoints(2)x, BezierPoints(2)y)
    StartPoint = BezierPoints(2)
    current = 0
    EndIf
    Next
    VectorSourceColor(RGBA(255, 0, 0, 255))
    StrokePath(2.0)
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ; show bars
    offset = 0
    ResetList(raw_data())
    ForEach raw_data()
    MovePathCursor(40 + offset, 560 - (raw_data()*3))
    AddPathLine(40 + offset, 560, #PB_Path_Default)
    offset + 50
    Next
    VectorSourceColor(RGBA(0, 0, 255, 255))
    StrokePath(10, #PB_Path_SquareEnd )
    StopVectorDrawing()
    EndIf
    Repeat
    Event = WaitWindowEvent()
    Until Event = #PB_Event_CloseWindow
    EndIf

    PS. I'm not sure those artifacts (line in some places is 'broken') can be fixed while using built-in PB function, maybe will need to make custom bezier code to use unlimited amount of points, not only 4 (however, then can be another problem - line will become 'too smooth' as the more points used, the less weight every single point will have on line drawing. But I remember there must be some tweaks like step, etc, later will take a look at my old bezier code to check how it all does ^^)
    PSS. Can also just try to define only 4 points from a whole data (1st point at 0%, 2nd at 33.33%, 3 on 66.66%, last on 100%) simply skipping all other points, but that definitely will made line 'very smooth'

    _________________
    Kind of copyleft notify: all the source code created by me and posted on Purebasic official forums is free to use and modification in all possible (and several impossible) ways for anyone, without asking my permission

    Last edited by Lunasole on Fri Aug 12, 2016 12:53 pm, edited 1 time in total.

    Top
    Posted: Fri Aug 12, 2016 12:50 pm
    Enthusiast

    Joined: Wed Sep 22, 2010 1:17 pm
    Posts: 352
    Location: United Kingdom
    @spikey said right about Bezier curves while he posted it.

    It subsequently occurred to me that AddPathCurve was the solution but Lunasole beat me to the punch


    Top
    Posted: Fri Aug 12, 2016 12:57 pm
    Addict

    Joined: Mon Oct 26, 2015 2:55 am
    Posts: 928
    Location: UA
    It subsequently occurred to me that AddPathCurve was the solution but Lunasole beat me to the punch :D

    It's anyway like partial solution :)
    Comment 83 stroke on that my example to make it's problem clearly visible (or maybe problem in my code)

    _________________
    Kind of copyleft notify: all the source code created by me and posted on Purebasic official forums is free to use and modification in all possible (and several impossible) ways for anyone, without asking my permission


    Top
    Posted: Fri Aug 12, 2016 2:11 pm
    Enthusiast

    Joined: Fri Oct 06, 2006 3:57 pm
    Posts: 570
    Location: England
    Thanks fopr the replies and code.
    I had tried addpathcurve albeit in a more roundabout fashion but got similar results.
    I dont understand however why the line doesn't always go though the midpoint of the curve ?
    With regard to what level of smoothness - i'm trying to duplicate a graph generated using excel so the line can have no sharp angles but must pass through each defined point. ( it's for a customer so the graph has to look pretty rather than realistic )


    Top
    Posted: Fri Aug 12, 2016 3:18 pm
    Enthusiast

    Joined: Wed Sep 22, 2010 1:17 pm
    Posts: 352
    Location: United Kingdom
    If by midpoint you mean the X2, Y2 arguments, it won't. The line is only guaranteed to go through the start point (current cursor position) and the end point (the X3, Y3 arguments). The X1, Y1, and X2, Y2 control points describe the shape of the curve rather than defining specific points on it.
    See the first diagram in this article and also the animation in the section 'Constructing Bézier curves' which shows what's going on.
    https://en.wikipedia.org/wiki/B%C3%A9zier_curve. P0 is the current cursor.
    Think of the relationship between a circle and a tangent. The tangent is a line which describes the slope of the circle at any point on its circumference but doesn't form a part of the circle (except where the tangent and the circumference intersect of course). The X1, Y1, and X2, Y2 perform a similar task but with two dimensions.


    Top

    Beziercode 1 264

    Posted: Fri Aug 12, 2016 3:29 pm
    Enthusiast

    Joined: Fri Oct 06, 2006 3:57 pm
    Posts: 570
    Location: England
    Ah, thanks for that - i'd always assumed the line always passed through the midpoint (x2, y2) which is why I though my own effort using beziers was faulty.


    Top
    Posted: Fri Aug 12, 2016 11:12 pm
    Addict

    Joined: Mon Oct 26, 2015 2:55 am
    Posts: 928
    Location: UA
    @captain_skank, here I've got some code for Beziers, you can try experiments with it
    viewtopic.php?f=12&t=66378&p=492790#p492790
    Also there is a code around it which clearly does what you described (smoothly draws line through all key points), as shapes on this fully procedural-generated image for example (http://rgho.st/6hcb9nSHb) [they are smooth internally, just image pixelized by design - there were 2D-terrains for old Worms Armageddon], but for now I failed to understand and port that code ^^ My own code written in VB6 years ago with a lack of detailed comments..
    Well maybe will do it later, as I anyway soon might need the same stuff as in your task

    _________________
    Kind of copyleft notify: all the source code created by me and posted on Purebasic official forums is free to use and modification in all possible (and several impossible) ways for anyone, without asking my permission


    Top

    Beziercode 1 26th

    Posted: Tue Oct 11, 2016 3:03 pm
    Enthusiast

    Joined: Fri Oct 06, 2006 3:57 pm
    Posts: 570
    Location: England
    Finaly had a bit more time to look at this but still cannot get a smooth line.
    Also using Lunasole's code - the line doen't reflect the actual data points, but perhaps i'm using it incorrectly.
    Procedure GetBezierX(Array Points.POINT(1), BStep.d)
    Protected Dim OutPoints.POINT (1 + Int(1 / bStep)), OutNum
    Protected.d t, xt, yt
    ; prepare starting points
    Protected Dim CPoints.POINT(0)
    CopyArray(Points(), CPoints())
    Protected Cnt, AllX, AllY, Max = ArraySize(CPoints())
    For Cnt = 1 To Max - 1
    CPoints(Cnt)x = Max * (Points(Cnt)x - Points(Cnt-1)x) - AllX
    CPoints(Cnt)y = Max * (Points(Cnt)y - Points(Cnt-1)y) - AllY
    ALLX + CPoints(Cnt)x
    ALLY + CPoints(Cnt)y
    Next cnt
    CPoints(Max)x = (Points(Max)x - Points(0)x) - AllX
    CPoints(Max)y = (Points(Max)y - Points(0)y) - AllY
    ; generate output curves
    While t < 1.0
    xt = 0
    yt = 0
    For Cnt = Max To 1 Step -1
    xt + CPoints(Cnt)x * Pow(t, Cnt)
    yt + CPoints(Cnt)y * Pow(t, Cnt)
    Next Cnt
    xt + Points(0)x
    yt + Points(0)y
    OutPoints(OutNum)x = xt
    OutPoints(OutNum)y = yt
    OutNum + 1
    t + BStep
    Wend
    ; return
    ReDim OutPoints(OutNum - 1)
    CopyArray(OutPoints(), Points())
    EndProcedure
    NewList raw_data()
    AddElement(raw_data())
    raw_data() = 00
    AddElement(raw_data())
    raw_data() = 02
    AddElement(raw_data())
    raw_data() = 08
    AddElement(raw_data())
    raw_data() = 18
    AddElement(raw_data())
    raw_data() = 32
    AddElement(raw_data())
    raw_data() = 47
    AddElement(raw_data())
    raw_data() = 63
    AddElement(raw_data())
    raw_data() = 79
    AddElement(raw_data())
    raw_data() = 91
    AddElement(raw_data())
    raw_data() = 98
    AddElement(raw_data())
    raw_data() = 99
    AddElement(raw_data())
    raw_data() = 99
    ListSize(raw_data())
    Global Dim Test.POINT (ListSize(raw_data())-1)
    FirstElement(raw_data())
    counter = 0
    ForEach(raw_data())
    Test(counter)x = 50 * counter
    Test(counter)y = raw_data()
    counter + 1
    Next
    Define t
    For t = 0 To ArraySize(Test())-1
    ; printing point # and new coordinates of extrapolated line points
    Debug Str(t) + ' | X,Y = ' + #TAB$ + Str(Test(t)x) + #TAB$ + Str(Test(t)y)
    Next t
    Debug ' - - - - - - - - - - - - - - - - - - - - - '
    GetBezierX(Test(), 0.01)
    Define t
    For t = 0 To ArraySize(Test())-1
    ; printing point # and new coordinates of extrapolated line points
    Debug Str(t) + ' | X,Y = ' + #TAB$ + Str(Test(t)x) + #TAB$ + Str(Test(t)y)
    Next t
    If OpenWindow(0, 0, 0, 800, 600, 'VectorDrawing', #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
    CanvasGadget(0, 0, 0, 800, 600)
    If StartVectorDrawing(CanvasVectorOutput(0))
    ScaleCoordinates(5, 3)
    ; draw axis
    MovePathCursor(40, 40)
    AddPathLine(0, 100, #PB_Path_Relative)
    AddPathLine(100, 0, #PB_Path_Relative)
    VectorSourceColor(RGBA(0, 0, 0, 255))
    StrokePath(1, #PB_Path_SquareEnd )
    ; plot data points
    offset = 0
    ResetList(raw_data())
    ForEach raw_data()
    AddPathCircle(40 + offset, 40 + (100 - raw_data()), 1)
    offset + (100/11)
    Next
    VectorSourceColor(RGBA(255, 0, 0, 255))
    StrokePath(1, #PB_Path_Default )
    ; ; Plot bar graph
    ; offset = 0
    ; ResetList(raw_data())
    ; ForEach raw_data()
    ; MovePathCursor(40 + offset, 40 + (100 - raw_data()))
    ; AddPathLine(0, raw_data(), #PB_Path_Relative)
    ; offset + (100/11)
    ; Next
    ; VectorSourceColor(RGBA(0, 0, 255, 255))
    ; StrokePath(1, #PB_Path_SquareEnd )
    ; plot smooth line
    MovePathCursor(40, 140)
    For t = 1 To ArraySize(Test())
    AddPathLine(1, last_y-Test(t)y, #PB_Path_Relative)
    last_y = Test(t)y
    Next t
    VectorSourceColor(RGBA(0, 0, 255, 255))
    StrokePath(1, #PB_Path_RoundCorner)
    StopVectorDrawing()
    EndIf
    Repeat
    Event = WaitWindowEvent()
    Until Event = #PB_Event_CloseWindow
    EndIf


    Top
    Page 1 of 1
    [ 10 posts ]