This notebook sets up the linear algebra to map from the geometry matrix specifying a Bezier curve through to the parametric, cubic, form of the x, y and z coordinates of the curve.
var('t')
var('x1,y1,z1,x2,y2,z2,x3,y3,z3,x4,y4,z4')
TV = Matrix(SR, 4,1, ((t**3,t**2,t,1)))
MB = Matrix(ZZ, 4,4, ((-1,3,-3,1),(3,-6,3,0),(-3,3,0,0),(1,0,0,0)))
GB = Matrix(SR, 4,3, ((x1,y1,z1),(x2,y2,z2),(x3,y3,z3),(x4,y4,z4))).transpose()
QT = GB * MB * TV
pretty_print(GB, MB, TV)
pretty_print(LatexExpr("x(t) = "), QT[0,0])
pretty_print(LatexExpr("y(t) = "), QT[1,0])
pretty_print(LatexExpr("z(t) = "), QT[2,0])
Here is the same basic workup, but now using actual values for the geometry matrix. As it turns out this curve has no inflection points.
P1 = (100,100,0)
P2 = (100,150,0)
P3 = (150,200,0)
P4 = (200,200,0)
GB = Matrix(SR, 4,3, (P1,P2,P3,P4)).transpose()
QT = GB * MB * TV
gpoly = polygon([[GB[0,i],GB[1,i]] for i in range(4)],rgbcolor=(0.0,0.5,0.0),alpha=0.5)
gplot = parametric_plot((QT[0,0],QT[1,0]),(t, 0.0,1.0),color=(1.0,0.0,0.0))
fig = gpoly + gplot
fig.show()
This example is a bit more subtle, and makes the point that a straight line segment is entirely possible using the geometry specification for a Bezier Curve
P1 = (100,100,0)
P2 = (103,103,0)
P3 = (197,197,0)
P4 = (200,200,0)
GB = Matrix(SR, 4,3, (P1,P2,P3,P4)).transpose()
QT = GB * MB * TV
gpoly = polygon([[GB[0,i],GB[1,i]] for i in range(4)],rgbcolor=(0.0,0.5,0.0),alpha=0.5)
gplot = parametric_plot((QT[0,0],QT[1,0]),(t, 0.0,1.0),color=(1.0,0.0,0.0))
fig = gpoly + gplot
fig.show()
It is entirely possible to force a Bezier Curve to intersect itself. In this next example, pay attention to the statement that the curve must remain inside the convex hull of the four points. It is not true, as you can see, that the curve remains inside a polygon with vertices enumerated in order.
P1 = ( 200,100,0)
P2 = ( 200,400,0)
P3 = ( 0,200,0)
P4 = ( 300,200,0)
GB = Matrix(SR, 4,3, (P1,P2,P3,P4)).transpose()
QT = GB * MB * TV
gpoly = polygon([[GB[0,i],GB[1,i]] for i in range(4)],rgbcolor=(0.0,0.5,0.0),alpha=0.5)
gplot = parametric_plot((QT[0,0],QT[1,0]),(t, 0.0,1.0),color=(1.0,0.0,0.0))
fig = gpoly + gplot
fig.show()
As our development is for a 3D curve, here is a truly 3D curve. Notice that this curve does not lie in a plane.
P1 = ( 0, 0, 0)
P2 = (100, 0, 0)
P3 = ( 0, 100, 100)
P4 = ( 0, 0, 100)
GB = Matrix(SR, 4,3, (P1,P2,P3,P4)).transpose()
QT = GB * MB * TV
#gpoly = polygon([[GB[0,i],GB[1,i],GB[2,i]] for i in range(4)],rgbcolor=(0.0,0.5,0.0),alpha=0.5)
gplot = parametric_plot3d((QT[0,0],QT[1,0],QT[2,0]),(t, 0.0,1.0),color=(0.2,0.2,0.6),thickness=8)
fig = gplot
fig += point3d(P1,color=(1.0,0.0,0.0),size=16)
fig += point3d(P2,color=(0.0,1.0,0.0),size=16)
fig += point3d(P3,color=(0.0,0.0,1.0),size=16)
fig += point3d(P4,color=(0.8,0.8,0.0),size=16)
fig.show()