B-Splines Curves

Ross Beveridge, December 5, 2019

This notebook shows how B-Spline segments come together to form a longer spine curve. Several things are make geometrically clear by actually plotting the curve. First, colors are used so the individual curve segments standout. Second, the repition of control points to force a spline curve to start (or end) at a designated point. Third, generally the curve does not evey pass through a specific control point.  

In [43]:
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 [44]:
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)],size=50,color=(0.2,0.2,0.2))
# 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), thickness=4)
# 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), thickness=4)
# 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), thickness=4)
# 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), thickness=4)
fig  = seg1 + seg2 + seg3 + seg4 + pts
fig.show(figsize=9)

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 [45]:
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))
pts  = point2d([(CPS[0,i],CPS[1,i]) for i in range(10)],size=50,color=(0.2,0.2,0.2))
# 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), thickness=4)
# 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), thickness=4)
# 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), thickness=4)
# 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), thickness=4)
# 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), thickness=4)
# 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), thickness=4)
# 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), thickness=4)
# 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), thickness=4)
# Generate figure elements then show
fig  = seg1 + seg2 + seg3 + seg4 + seg5 + seg6 + seg7 + seg8 + pts
fig.show(figsize=9)