B-Splines Curves

Ross Beveridge, December 4, 2018

This notebook shows how B-Spline segments come together to form a longer spine curve.  

In [68]:
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,0,3,0),(1,4,1,0)))
MB = MB.transpose()
MB = (1/6)*MB
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])

Example 1: A 4 Segment B-Spline.

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.

In [69]:
P1 = (200,100,0)
P2 = (500,200,0)
P3 = (600,500,0)
P4 = (800,600,0)
P5 = (500,900,0)
P6 = (400,700,0)
P7 = (100,500,0)
# All points
CPS  = Matrix(SR, 7,3, (P1,P2,P3,P4,P5,P6,P7)).transpose()
pts  = point2d((CPS[0][i],CPS[1][i]) for i in range(7))
# segment 1
GB1  = Matrix(SR, 4,3, (P1,P2,P3,P4)).transpose()
QT1  = GB1 * MB * TV
seg1 = parametric_plot((QT1[0,0],QT1[1,0]),(t, 0.0,1.0),color=(0.0,1.0,0.0))
# segment 2
GB2  = Matrix(SR, 4,3, (P2,P3,P4,P5)).transpose()
QT2  = GB2 * MB * TV
seg2 = parametric_plot((QT2[0,0],QT2[1,0]),(t, 0.0,1.0),color=(1.0,0.0,0.0))
# segment 3
GB3  = Matrix(SR, 4,3, (P3,P4,P5,P6)).transpose()
QT3  = GB3 * MB * TV
seg3 = parametric_plot((QT3[0,0],QT3[1,0]),(t, 0.0,1.0),color=(0.0,0.0,1.0))
# segment 2
GB4  = Matrix(SR, 4,3, (P4,P5,P6,P7)).transpose()
QT4  = GB4 * MB * TV
seg4 = parametric_plot((QT4[0,0],QT4[1,0]),(t, 0.0,1.0),color=(1.0,0.0,1.0))
fig  = seg1 + seg2 + seg3 + seg4 + pts
fig.show()

Example 2: Repeating Control Points.

This example is similar to that above, but using one of the simplest tricks to get the curve to start and stop on a designated point.

In [99]:
P1  = (200,100,0)
P2  = (200,100,0)
P3  = (200,100,0)
P4  = (500,200,0)
P5  = (600,500,0)
P6  = (800,600,0)
P7  = (500,900,0)
P8  = (400,700,0)
P9  = (100,500,0)
P10 = (100,500,0)
P11 = (100,500,0)
# All points
CPS  = Matrix(SR, 10,3, (P1,P2,P3,P4,P5,P6,P7,P8,P9,P10)).transpose()
pts  = point2d((CPS[0][i],CPS[1][i]) for i in range(10))
# segment 1
GB1  = Matrix(SR, 4,3, (P1,P2,P3,P4)).transpose()
QT1  = GB1 * MB * TV
seg1 = parametric_plot((QT1[0,0],QT1[1,0]),(t, 0.0,1.0),color=(0.0,1.0,0.0))
# segment 2
GB2  = Matrix(SR, 4,3, (P2,P3,P4,P5)).transpose()
QT2  = GB2 * MB * TV
seg2 = parametric_plot((QT2[0,0],QT2[1,0]),(t, 0.0,1.0),color=(1.0,0.0,0.0))
# segment 3
GB3  = Matrix(SR, 4,3, (P3,P4,P5,P6)).transpose()
QT3  = GB3 * MB * TV
seg3 = parametric_plot((QT3[0,0],QT3[1,0]),(t, 0.0,1.0),color=(0.0,0.0,1.0))
# segment 4
GB4  = Matrix(SR, 4,3, (P4,P5,P6,P7)).transpose()
QT4  = GB4 * MB * TV
seg4 = parametric_plot((QT4[0,0],QT4[1,0]),(t, 0.0,1.0),color=(1.0,0.0,1.0))
# segment 5
GB5  = Matrix(SR, 4,3, (P5,P6,P7,P8)).transpose()
QT5  = GB5 * MB * TV
seg5 = parametric_plot((QT5[0,0],QT5[1,0]),(t, 0.0,1.0),color=(0.5,0.5,0.0))
# segment 6
GB6  = Matrix(SR, 4,3, (P6,P7,P8,P9)).transpose()
QT6  = GB6 * MB * TV
seg6 = parametric_plot((QT6[0,0],QT6[1,0]),(t, 0.0,1.0),color=(0.0,1.0,1.0))
# segment 7
GB7  = Matrix(SR, 4,3, (P7,P8,P9,P10)).transpose()
QT7  = GB7 * MB * TV
seg7 = parametric_plot((QT7[0,0],QT7[1,0]),(t, 0.0,1.0),color=(0.5,0.0,0.5))
# segment 8
GB8  = Matrix(SR, 4,3, (P8,P9,P10,P11)).transpose()
QT8  = GB8 * MB * TV
seg8 = parametric_plot((QT8[0,0],QT8[1,0]),(t, 0.0,1.0),color=(0.7,0.8,0.3))
# Generate figure elements then show
fig  = seg1 + seg2 + seg3 + seg4 + seg5 + seg6 + seg7 + seg8 + pts
fig.show()