Bezier Curves

In [18]:
import numpy as np
from scipy.special import comb
import matplotlib.pyplot as plt
In [19]:
%matplotlib inline
In [ ]:
# Use this to click points for Bezier curve
# Might have to run this block twice. (?)
%matplotlib osx
plt.ion()

Bernstein polynomials

In [20]:
def B(i, N, t):
    val = comb(N,i) * t**i * (1.-t)**(N-i)
    return val

Plot the Bernstein polynomials

In [21]:
tt = np.linspace(0, 1, 100)
In [22]:
N = 7
for i in range(N+1):
    plt.plot(tt, B(i, N, tt));

Bezier Curves

In [23]:
def P(t, X):
    '''
     xx = P(t, X)
     
     Evaluates a Bezier curve for the points in X.
     
     Inputs:
      X is a list (or array) or 2D coords
      t is a number (or list of numbers) in [0,1] where you want to
        evaluate the Bezier curve
      
     Output:
      xx is the set of 2D points along the Bezier curve
    '''
    X = np.array(X)
    N,d = np.shape(X)   # Number of points, Dimension of points
    N = N - 1
    xx = np.zeros((len(t), d))
    
    for i in range(N+1):
        xx += np.outer(B(i, N, t), X[i])
    
    return xx
In [24]:
plt.figure(2, figsize=[8,8])
plt.clf()

clickable = False

if clickable:
    plt.plot([0,1],[0,1],'w.')
    plt.axis('equal');
    plt.draw()
    c = plt.ginput(20, mouse_stop=2) # on macbook, alt-click to stop
    plt.draw()
else:
    c = [(0.09374999999999989, 0.15297619047619054),
         (0.549107142857143, 0.1648809523809524),
         (0.7083333333333335, 0.6142857142857144),
         (0.5282738095238095, 0.8940476190476193),
         (0.24404761904761907, 0.8776785714285716),
         (0.15327380952380942, 0.6321428571428573),
         (0.580357142857143, 0.08303571428571432),
         (0.8839285714285716, 0.28988095238095246)]
    
X = np.array(c)

tt = np.linspace(0, 1, 200)
xx = P(tt, X)

plt.plot(xx[:,0], xx[:,1])
plt.plot(X[:,0], X[:,1], 'ro');

TrueType Fonts

In [25]:
def DrawBezier(p, n):

    x1 = p[0]
    y1 = p[1]
    x2 = p[2]
    y2 = p[3]
    x3 = p[4]
    y3 = p[5]
    x4 = p[6]
    y4 = p[7]
        
    t = np.linspace(0,1,n)
    
    xx = P(t, np.reshape(p, (4,2)))
    
    plt.plot([x1, x4], [y1, y4], 'ro') # knot point
    plt.plot([x1, x2], [y1, y2], 'r-') # tangent
    plt.plot([x3, x4], [y3, y4], 'r-') # tangent
    plt.plot(xx[:,0], xx[:,1], '-')                # curve
In [26]:
# 5
p = [[149, 597, 149, 597, 149, 597, 345, 597],
    [345, 597, 361, 597, 365, 599, 368, 606],
    [368, 606, 406, 695, 368, 606, 406, 695],
    [406, 695, 397, 702, 406, 695, 397, 702],
    [397, 702, 382, 681, 372, 676, 351, 676],
    [351, 676, 351, 676, 142, 676, 142, 676],
    [142, 676,  33, 439, 142, 676,  33, 439],
    [33,  439,  32, 438,  32, 436,  32, 434],
    [32,  434,  32, 428,  35, 426,  44, 426],
    [44,  426,  74, 426, 109, 420, 149, 408],
    [149, 408, 269, 372, 324, 310, 324, 208],
    [324, 208, 324, 112, 264,  37, 185,  37],
    [185,  37, 165,  37, 149,  44, 119,  66],
    [119,  66,  86,  90,  65,  99,  42,  99],
    [42,   99,  14,  99,   0,  87,   0,  62],
    [0,    62,   0,  24,  46,   0, 121,   0],
    [121,   0, 205,   0, 282,  27, 333,  78],
    [333,  78, 378, 123, 399, 180, 399, 256],
    [399, 256, 399, 327, 381, 372, 333, 422],
    [333, 422, 288, 468, 232, 491, 112, 512],
    [112, 512, 112, 512, 149, 597, 149, 597]]
In [27]:
plt.figure(3, figsize=[8,8])
plt.clf()
for segment in p:
    DrawBezier(segment, 100)
plt.axis('equal');
In [28]:
# T,
p = [[237, 620, 237, 620, 237, 120, 237, 120],
     [237, 120, 237,  35, 226,  24, 143,  19],
     [143,  19, 143,  19, 143,   0, 143,   0],
     [143,   0, 143,   0, 435,   0, 435,   0],
     [435,   0, 435,   0, 435,  19, 435,  19],
     [435,  19, 353,  23, 339,  36, 339, 109],
     [339, 109, 339, 108, 339, 620, 339, 620],
     [339, 620, 339, 620, 393, 620, 393, 620],
     [393, 620, 507, 620, 529, 602, 552, 492],
     [552, 492, 552, 492, 576, 492, 576, 492],
     [576, 492, 576, 492, 570, 662, 570, 662],
     [570, 662, 570, 662,   6, 662,   6, 662],
     [6,   662,   6, 662,   0, 492,   0, 492],
     [0,   492,   0, 492,  24, 492,  24, 492],
     [24,  492,  48, 602,  71, 620, 183, 620],
     [183, 620, 183, 620, 237, 620, 237, 620]]
In [29]:
plt.figure(3, figsize=[8,8])
plt.clf()
for segment in p:
    DrawBezier(segment, 100)
plt.axis('equal');
In [35]:
# f
p = [[289, 452, 289, 452, 166, 452, 166, 452],
    [166, 452, 166, 452, 166, 568, 166, 568],
    [166, 568, 166, 627, 185, 657, 223, 657],
    [223, 657, 245, 657, 258, 647, 276, 618],
    [276, 618, 292, 589, 304, 580, 321, 580],
   #[321, 580, 345, 580, 363, 598, 363, 621],
    [321, 580, 345, 580, 363, 598, 363, 621],
    [363, 621, 363, 657, 319, 683, 259, 683],
   #[259, 683, 196, 683, 144, 656, 118, 611],
   #[118, 611,  92, 566,  84, 530,  83, 450],
    [259, 683, 196, 683, 126, 666, 100, 621],
    [100, 621,  74, 576,  84, 530,  83, 450],
    [ 83, 450,  83, 450,   1, 450,   1, 450],
    [  1, 450,   1, 450,   1, 418,   1, 418],
    [  1, 418,   1, 418,  83, 418,  83, 418],
    [ 83, 418,  83, 418,  83, 104,  83, 104],
    [ 83, 104,  83,  31,  72,  19,   0,  15],
    [  0,  15,   0,  15,   0,   0,   0,   0],
    [  0,   0,   0,   0, 260,   0, 260,   0],
    [260,   0, 260,   0, 260,  15, 260,  15],
    [260,  15, 178,  18, 167,  29, 167, 104],
    [167, 104, 167, 104, 167, 418, 167, 418],
    [167, 418, 167, 418, 289, 418, 289, 418],
    [289, 418, 289, 418, 289, 452, 289, 452]]
In [36]:
plt.figure(3, figsize=[8,8])
plt.clf()
for segment in p:
    DrawBezier(segment, 100)
idx = 5
plt.plot([p[idx][0], p[idx][-2]], [p[idx][1], p[idx][-1]], 'ko')
plt.axis('equal');

Let's try warping a segment!

In [37]:
p[idx]
Out[37]:
[321, 580, 345, 580, 363, 598, 363, 621]
In [38]:
p[idx][2] -= 60
p[idx][3] -= 50
In [39]:
plt.figure(4, figsize=[8,8])
plt.clf()
for segment in p:
    DrawBezier(segment, 100)
idx = 5
plt.plot([p[idx][0], p[idx][-2]], [p[idx][1], p[idx][-1]], 'ko')
plt.axis('equal');
In [ ]: