Exercise 7: Bézier Curve

Given the vertices of a Bézier polygon (see fig below):

$P 0 = (1; 1)$

$P 1 = (2; 3)$

$P 2 = (4; 3)$

$P 4 = (3; 1)$

Determine 7 points on the Bezier curve defined by these points.


In [32]:
%matplotlib inline
import numpy
import pylab
import matplotlib.pyplot as plt

class Key:
    def __init__(self):
        self.time = 0
        self.in_tangent = numpy.array([0, 0, 0])
        self.out_tangent = numpy.array([0, 0, 0])
        self.value = numpy.array([0, 0, 0])

class CurveSplineBezier:
    def __init__(self):
        self.keys = []
        self.plt = plt
        
        self.setup_plot()
    
    def matrix(self):
        return numpy.matrix(
            (
                (-1,  3, -3,  1),
                ( 3, -6,  3,  0),
                (-3,  3,  0,  0),
                ( 1,  0,  0,  0)
            )
        )
        
    def start_time(self):
        return self.keys[0].time

    def end_time(self):
        return self.keys[-1].time
    
    def number_of_keys(self):
        return len(self.keys)
    
    def get_key_time(self, index):
        return self.keys[index].time
    
    def set_key_time(self, index, time):
        if self.keys[index - 1].time > time:
            return False
        
        self.keys[index].time = time
        
    def get_key_value(self, index):
        return self.keys[index].value
    
    def set_key_value(self, index, value):
        self.keys[index].value = value
        
    def evaluate(self, time):
        if len(self.keys) < 1:
            return False
        
        elif len(self.keys) < 2:
            return self.keys[-1].value
        
        elif (
            time < self.keys[0].time
            or
            time > self.keys[-1].time
        ):
            return False
        
        if time == self.keys[0].time:
            return self.keys[0].value
        
        if time == self.keys[-1].time:
            return self.keys[-1].value
        
        for index, key in self.keys:
            if time >= key.time and time < self.keys[index + 1].time:
                current_time = (time - key.time) / (self.keys[index + 1].time - key.time)
                
                return self.interpolate(index, index + 1, current_time)
        
    def setup_plot(self):
        self.plt.margins(0.1)
        self.plt.grid()
        
    def interpolate(self, start_key, end_key, time):
        matrix = self.matrix()
        t3 = time**3
        
        x = t3 * matrix[0].A[0][0] + t3 * matrix[1].A[0][0] + t3 * matrix[2].A[0][0] + t3 * matrix[3].A[0][0]
        y = t3 * matrix[0].A[0][1] + t3 * matrix[1].A[0][1] + t3 * matrix[2].A[0][1] + t3 * matrix[3].A[0][1]
        z = t3 * matrix[0].A[0][2] + t3 * matrix[1].A[0][2] + t3 * matrix[2].A[0][2] + t3 * matrix[3].A[0][2]
        w = t3 * matrix[0].A[0][3] + t3 * matrix[1].A[0][3] + t3 * matrix[2].A[0][3] + t3 * matrix[3].A[0][3]
        
        start = self.keys[start_key].value
        end = self.keys[end_key].value
        out_tangent = self.keys[start_key].out_tangent
        in_tangent = self.keys[end_key].in_tangent
        
        return np.array([
            x * start[0] + y * end[0] + z * out_tangent[0] + w * in_tangent[0],
            x * start[1] + y * end[1] + z * out_tangent[1] + w * in_tangent[1],
            x * start[2] + y * end[2] + z * out_tangent[2] + w * in_tangent[2]
        ])
    
    def add_key(self, key):
        new_key = Key()
        new_key.time = key.time
        new_key.in_tangent = (key.value - key.in_tangent) * 3
        new_key.out_tangent = (key.out_tangent - key.value) * 3
        
        if len(self.keys) > 0:
            if self.keys[-1].time < key.time:
                self.keys.append(new_key)
                return
                
            elif self.keys[0].time > key.time:
                self.keys.insert(0, new_key)
                return                
        
            for index, key_ in self.keys:
                if key_.time > key.time:
                    self.keys.insert(index, new_key)
                    return
        else:
            self.keys.append(new_key)

In [39]:
key0 = Key()
key0.value = numpy.array([1, 1, 0])
key1 = Key()
key1.value = numpy.array([2, 3, 0])

curve = CurveSplineBezier()
curve.add_key(key0)
#curve.add_key(key1)


Out[39]:
False

In [ ]: