From 51f76f069296d3441f592a688500d723bb0e4dbb Mon Sep 17 00:00:00 2001 From: fk03983 Date: Thu, 23 Jan 2020 21:40:19 -0600 Subject: [PATCH 1/7] Added bezier curve --- graphics/bezier_curve.py | 100 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 graphics/bezier_curve.py diff --git a/graphics/bezier_curve.py b/graphics/bezier_curve.py new file mode 100644 index 000000000000..87920812b031 --- /dev/null +++ b/graphics/bezier_curve.py @@ -0,0 +1,100 @@ +#https://en.wikipedia.org/wiki/B%C3%A9zier_curve +#https://www.tutorialspoint.com/computer_graphics/computer_graphics_curves.htm + +from typing import List, Tuple +import scipy.special as sp + +class BezierCurve: + """ + A class to generate bezier curves for a given set of points. The implementation works only for 2d points. + """ + def __init__(self, list_of_points: List[Tuple]): + """ + The constructor of the Bezier Curve class. + list_of_points: List of tuples on which to interpolate. + """ + self.list_of_points = list_of_points + self.degree = len(list_of_points) - 1 #degree of the curve produced will be n - 1 + + def basis_function(self, t: float) -> List[float]: + """ + The function to cater the need for the basis function. + t: the 1-d co-ordinate at which to evaluate the basis function(s). + returns a returns list of floating point numbers, a number at index i represents the value of + basis function i at t. + + >>> curve1 = BezierCurve([(1,1), (1,2)]) + >>> curve1.basis_function(0) + [1.0, 0.0] + >>> curve1.basis_function(1) + [0.0, 1.0] + """ + output_values: List[float] = list() + for i in range(len(self.list_of_points)): + output_values.append(sp.comb(self.degree, i) * ((1 - t) ** (self.degree - i)) * (t ** i)) #basis function for each i + + assert round(sum(output_values),5) == 1 #the basis must sum up to 1 for it to produce a valid bezier curve. + return output_values + + def bezier_curve_function(self, t: float) -> Tuple[float, float]: + """ + The function to produce the values of the bezier curve at time t. At t = 0, + it must return the first point, and at t = 1, it must return the last point. + t: the value of t at which to evaluate the bezier function + returns a 2-d tuple of floats, representing the value of the bezier curve at the given t. + + >>> curve1 = BezierCurve([(1,1), (1,2)]) + >>> curve1.bezier_curve_function(0) + (1.0, 1.0) + >>> curve1.bezier_curve_function(1) + (1.0, 2.0) + """ + basis_function = self.basis_function(t) + x = 0.0 + y = 0.0 + for i in range(len(self.list_of_points)): #summing up the product of ith basis function and ith point, for all points + x += basis_function[i] * self.list_of_points[i][0] + y += basis_function[i] * self.list_of_points[i][1] + + return (x,y) + + def plot_curve(self, step_size: float = 0.01) : + """ + plots the bezier curve using matplotlib plotting function. + step_size: defines the step(s) at which to evaluate the bezier curve and plot. The smaller the step size, + the finer the curve produced. + """ + import matplotlib.pyplot as plt + + to_plot_x: List[float] = [] # x coordinates of points to plot + to_plot_y: List[float] = [] # y coordinates of points to plot + + t = 0 + while t <= 1: + value = self.bezier_curve_function(t) + to_plot_x.append(value[0]) + to_plot_y.append(value[1]) + t += step_size + + x = [i[0] for i in self.list_of_points] + y = [i[1] for i in self.list_of_points] + + plt.scatter(x , y, color = 'red', label = "Control Points") + plt.plot(to_plot_x,to_plot_y, color = 'blue', label = "Curve") + plt.legend() + plt.show() + +if __name__ == "__main__": + import doctest + doctest.testmod() + + curve1 = BezierCurve([(1,2), (3,5)]) + curve1.plot_curve() + + curve1 = BezierCurve([(0, 0), (5, 5), (5, 0)]) + curve1.plot_curve() + + + + + From c6aacdd2b4461e68ebdbeb1d7564224314bfcc0f Mon Sep 17 00:00:00 2001 From: fk03983 Date: Thu, 23 Jan 2020 21:41:36 -0600 Subject: [PATCH 2/7] black formatted --- graphics/bezier_curve.py | 43 +++++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/graphics/bezier_curve.py b/graphics/bezier_curve.py index 87920812b031..e17048af292b 100644 --- a/graphics/bezier_curve.py +++ b/graphics/bezier_curve.py @@ -1,20 +1,24 @@ -#https://en.wikipedia.org/wiki/B%C3%A9zier_curve -#https://www.tutorialspoint.com/computer_graphics/computer_graphics_curves.htm +# https://en.wikipedia.org/wiki/B%C3%A9zier_curve +# https://www.tutorialspoint.com/computer_graphics/computer_graphics_curves.htm from typing import List, Tuple import scipy.special as sp + class BezierCurve: """ A class to generate bezier curves for a given set of points. The implementation works only for 2d points. """ + def __init__(self, list_of_points: List[Tuple]): """ The constructor of the Bezier Curve class. list_of_points: List of tuples on which to interpolate. """ self.list_of_points = list_of_points - self.degree = len(list_of_points) - 1 #degree of the curve produced will be n - 1 + self.degree = ( + len(list_of_points) - 1 + ) # degree of the curve produced will be n - 1 def basis_function(self, t: float) -> List[float]: """ @@ -31,9 +35,13 @@ def basis_function(self, t: float) -> List[float]: """ output_values: List[float] = list() for i in range(len(self.list_of_points)): - output_values.append(sp.comb(self.degree, i) * ((1 - t) ** (self.degree - i)) * (t ** i)) #basis function for each i + output_values.append( + sp.comb(self.degree, i) * ((1 - t) ** (self.degree - i)) * (t ** i) + ) # basis function for each i - assert round(sum(output_values),5) == 1 #the basis must sum up to 1 for it to produce a valid bezier curve. + assert ( + round(sum(output_values), 5) == 1 + ) # the basis must sum up to 1 for it to produce a valid bezier curve. return output_values def bezier_curve_function(self, t: float) -> Tuple[float, float]: @@ -52,13 +60,15 @@ def bezier_curve_function(self, t: float) -> Tuple[float, float]: basis_function = self.basis_function(t) x = 0.0 y = 0.0 - for i in range(len(self.list_of_points)): #summing up the product of ith basis function and ith point, for all points + for i in range( + len(self.list_of_points) + ): # summing up the product of ith basis function and ith point, for all points x += basis_function[i] * self.list_of_points[i][0] y += basis_function[i] * self.list_of_points[i][1] - return (x,y) + return (x, y) - def plot_curve(self, step_size: float = 0.01) : + def plot_curve(self, step_size: float = 0.01): """ plots the bezier curve using matplotlib plotting function. step_size: defines the step(s) at which to evaluate the bezier curve and plot. The smaller the step size, @@ -66,8 +76,8 @@ def plot_curve(self, step_size: float = 0.01) : """ import matplotlib.pyplot as plt - to_plot_x: List[float] = [] # x coordinates of points to plot - to_plot_y: List[float] = [] # y coordinates of points to plot + to_plot_x: List[float] = [] # x coordinates of points to plot + to_plot_y: List[float] = [] # y coordinates of points to plot t = 0 while t <= 1: @@ -79,22 +89,19 @@ def plot_curve(self, step_size: float = 0.01) : x = [i[0] for i in self.list_of_points] y = [i[1] for i in self.list_of_points] - plt.scatter(x , y, color = 'red', label = "Control Points") - plt.plot(to_plot_x,to_plot_y, color = 'blue', label = "Curve") + plt.scatter(x, y, color="red", label="Control Points") + plt.plot(to_plot_x, to_plot_y, color="blue", label="Curve") plt.legend() plt.show() + if __name__ == "__main__": import doctest + doctest.testmod() - curve1 = BezierCurve([(1,2), (3,5)]) + curve1 = BezierCurve([(1, 2), (3, 5)]) curve1.plot_curve() curve1 = BezierCurve([(0, 0), (5, 5), (5, 0)]) curve1.plot_curve() - - - - - From 10a09f824853987285e2bc9ab7a0a9b9709e4829 Mon Sep 17 00:00:00 2001 From: fk03983 Date: Thu, 23 Jan 2020 21:49:16 -0600 Subject: [PATCH 3/7] corrected spell check --- graphics/bezier_curve.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graphics/bezier_curve.py b/graphics/bezier_curve.py index e17048af292b..d8de2b6df92e 100644 --- a/graphics/bezier_curve.py +++ b/graphics/bezier_curve.py @@ -62,7 +62,7 @@ def bezier_curve_function(self, t: float) -> Tuple[float, float]: y = 0.0 for i in range( len(self.list_of_points) - ): # summing up the product of ith basis function and ith point, for all points + ): # summing up the product of i-th basis function and ith point, for all points x += basis_function[i] * self.list_of_points[i][0] y += basis_function[i] * self.list_of_points[i][1] From e7a5870e89ef8c53c26367d4839463e85cf6cfc1 Mon Sep 17 00:00:00 2001 From: fk03983 Date: Thu, 23 Jan 2020 22:01:44 -0600 Subject: [PATCH 4/7] edited scipy import --- graphics/bezier_curve.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/graphics/bezier_curve.py b/graphics/bezier_curve.py index d8de2b6df92e..550b0b27e986 100644 --- a/graphics/bezier_curve.py +++ b/graphics/bezier_curve.py @@ -2,7 +2,7 @@ # https://www.tutorialspoint.com/computer_graphics/computer_graphics_curves.htm from typing import List, Tuple -import scipy.special as sp +from scipy.special import comb class BezierCurve: @@ -36,7 +36,7 @@ def basis_function(self, t: float) -> List[float]: output_values: List[float] = list() for i in range(len(self.list_of_points)): output_values.append( - sp.comb(self.degree, i) * ((1 - t) ** (self.degree - i)) * (t ** i) + comb(self.degree, i) * ((1 - t) ** (self.degree - i)) * (t ** i) ) # basis function for each i assert ( From 59694ce4361fe91caf69b31faaf65d7302676e93 Mon Sep 17 00:00:00 2001 From: fk03983 Date: Fri, 24 Jan 2020 16:07:45 -0600 Subject: [PATCH 5/7] updated documentation for readablitity --- graphics/bezier_curve.py | 62 +++++++++++++++++++++++++--------------- 1 file changed, 39 insertions(+), 23 deletions(-) diff --git a/graphics/bezier_curve.py b/graphics/bezier_curve.py index 550b0b27e986..1ebcaa5e498c 100644 --- a/graphics/bezier_curve.py +++ b/graphics/bezier_curve.py @@ -7,25 +7,29 @@ class BezierCurve: """ - A class to generate bezier curves for a given set of points. The implementation works only for 2d points. + Generate bezier curves for a given set of points. + The implementation works only for 2d points. """ - def __init__(self, list_of_points: List[Tuple]): + def __init__(self, list_of_points: List[Tuple[float, float]]): """ The constructor of the Bezier Curve class. - list_of_points: List of tuples on which to interpolate. + list_of_points: Data points in the xy plane on which to interpolate. These + basically serve as the control points (control the behavior of curve), + of the bezier curve. """ self.list_of_points = list_of_points self.degree = ( - len(list_of_points) - 1 - ) # degree of the curve produced will be n - 1 + len(list_of_points) + - 1 # determines the flexibility of the curve. Degree = 1 produces a straight line. + ) def basis_function(self, t: float) -> List[float]: """ - The function to cater the need for the basis function. - t: the 1-d co-ordinate at which to evaluate the basis function(s). - returns a returns list of floating point numbers, a number at index i represents the value of - basis function i at t. + Bezier Curve is a weighted sum of the control points. Weight of each control point, as + a function of time t is called the basis function. + t: time value between 0 and 1 inclusive at which to evaluate the basis of the curve. + returns the x, y values of basis function at time t >>> curve1 = BezierCurve([(1,1), (1,2)]) >>> curve1.basis_function(0) @@ -33,15 +37,18 @@ def basis_function(self, t: float) -> List[float]: >>> curve1.basis_function(1) [0.0, 1.0] """ + assert 0 <= t <= 1 # t must be between 0 and 1 output_values: List[float] = list() for i in range(len(self.list_of_points)): + # basis function for each i output_values.append( comb(self.degree, i) * ((1 - t) ** (self.degree - i)) * (t ** i) - ) # basis function for each i + ) assert ( - round(sum(output_values), 5) == 1 - ) # the basis must sum up to 1 for it to produce a valid bezier curve. + round(sum(output_values), 5) + == 1 # the basis must sum up to 1 for it to produce a valid bezier curve. + ) return output_values def bezier_curve_function(self, t: float) -> Tuple[float, float]: @@ -49,7 +56,9 @@ def bezier_curve_function(self, t: float) -> Tuple[float, float]: The function to produce the values of the bezier curve at time t. At t = 0, it must return the first point, and at t = 1, it must return the last point. t: the value of t at which to evaluate the bezier function - returns a 2-d tuple of floats, representing the value of the bezier curve at the given t. + Returns the x, y coordinates of the Bezier curve at time t. + The first point in the curve is when t = 0. + The last point in the curve is when t = 1. >>> curve1 = BezierCurve([(1,1), (1,2)]) >>> curve1.bezier_curve_function(0) @@ -57,12 +66,14 @@ def bezier_curve_function(self, t: float) -> Tuple[float, float]: >>> curve1.bezier_curve_function(1) (1.0, 2.0) """ + + assert 0 <= t <= 1 # t must be between 0 and 1. + basis_function = self.basis_function(t) x = 0.0 y = 0.0 - for i in range( - len(self.list_of_points) - ): # summing up the product of i-th basis function and ith point, for all points + for i in range(len(self.list_of_points)): + # summing up the product of i-th basis function and i-th point, for all points. x += basis_function[i] * self.list_of_points[i][0] y += basis_function[i] * self.list_of_points[i][1] @@ -71,8 +82,8 @@ def bezier_curve_function(self, t: float) -> Tuple[float, float]: def plot_curve(self, step_size: float = 0.01): """ plots the bezier curve using matplotlib plotting function. - step_size: defines the step(s) at which to evaluate the bezier curve and plot. The smaller the step size, - the finer the curve produced. + step_size: defines the step(s) at which to evaluate the bezier curve and plot. + The smaller the step size, the finer the curve produced. """ import matplotlib.pyplot as plt @@ -89,8 +100,13 @@ def plot_curve(self, step_size: float = 0.01): x = [i[0] for i in self.list_of_points] y = [i[1] for i in self.list_of_points] + plt.plot( + to_plot_x, + to_plot_y, + color="blue", + label="Curve of Degree " + str(self.degree), + ) plt.scatter(x, y, color="red", label="Control Points") - plt.plot(to_plot_x, to_plot_y, color="blue", label="Curve") plt.legend() plt.show() @@ -100,8 +116,8 @@ def plot_curve(self, step_size: float = 0.01): doctest.testmod() - curve1 = BezierCurve([(1, 2), (3, 5)]) - curve1.plot_curve() + BezierCurve([(1, 2), (3, 5)]).plot_curve() # degree 1 + + BezierCurve([(0, 0), (5, 5), (5, 0)]).plot_curve() # degree 2 - curve1 = BezierCurve([(0, 0), (5, 5), (5, 0)]) - curve1.plot_curve() + BezierCurve([(0, 0), (5, 5), (5, 0), (2.5, -2.5)]).plot_curve() # degree 3 From a35987fbb5c628bcc349531eb60d77eb18feb0fd Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Sat, 25 Jan 2020 07:09:47 +0100 Subject: [PATCH 6/7] Update bezier_curve.py --- graphics/bezier_curve.py | 65 +++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 37 deletions(-) diff --git a/graphics/bezier_curve.py b/graphics/bezier_curve.py index 1ebcaa5e498c..211da71a4737 100644 --- a/graphics/bezier_curve.py +++ b/graphics/bezier_curve.py @@ -7,82 +7,75 @@ class BezierCurve: """ - Generate bezier curves for a given set of points. - The implementation works only for 2d points. + Bezier curve is a weighted sum of the control points. + Generate Bezier curves from a given set of control points. + The implementation works only for 2d points in the xy plane. """ def __init__(self, list_of_points: List[Tuple[float, float]]): """ - The constructor of the Bezier Curve class. - list_of_points: Data points in the xy plane on which to interpolate. These - basically serve as the control points (control the behavior of curve), - of the bezier curve. + list_of_points: Control points in the xy plane on which to interpolate. These + points control the behavior (shape) of the Bezier curve. """ self.list_of_points = list_of_points - self.degree = ( - len(list_of_points) - - 1 # determines the flexibility of the curve. Degree = 1 produces a straight line. - ) + # Degree determines the flexibility of the curve. + # Degree = 1 will produce a straight line. + self.degree = len(list_of_points) - 1 def basis_function(self, t: float) -> List[float]: """ - Bezier Curve is a weighted sum of the control points. Weight of each control point, as - a function of time t is called the basis function. - t: time value between 0 and 1 inclusive at which to evaluate the basis of the curve. + The basis function determines the weight of each control point at time t. + t: time value between 0 and 1 inclusive at which to evaluate the basis of + the curve. returns the x, y values of basis function at time t - >>> curve1 = BezierCurve([(1,1), (1,2)]) - >>> curve1.basis_function(0) + >>> curve = BezierCurve([(1,1), (1,2)]) + >>> curve.basis_function(0) [1.0, 0.0] - >>> curve1.basis_function(1) + >>> curve.basis_function(1) [0.0, 1.0] """ - assert 0 <= t <= 1 # t must be between 0 and 1 - output_values: List[float] = list() + assert 0 <= t <= 1, "Time t must be between 0 and 1." + output_values: List[float] = [] for i in range(len(self.list_of_points)): # basis function for each i output_values.append( comb(self.degree, i) * ((1 - t) ** (self.degree - i)) * (t ** i) ) - - assert ( - round(sum(output_values), 5) - == 1 # the basis must sum up to 1 for it to produce a valid bezier curve. - ) + # the basis must sum up to 1 for it to produce a valid Bezier curve. + assert round(sum(output_values), 5) == 1 return output_values def bezier_curve_function(self, t: float) -> Tuple[float, float]: """ - The function to produce the values of the bezier curve at time t. At t = 0, - it must return the first point, and at t = 1, it must return the last point. - t: the value of t at which to evaluate the bezier function + The function to produce the values of the Bezier curve at time t. + t: the value of time t at which to evaluate the Bezier function Returns the x, y coordinates of the Bezier curve at time t. The first point in the curve is when t = 0. The last point in the curve is when t = 1. - >>> curve1 = BezierCurve([(1,1), (1,2)]) - >>> curve1.bezier_curve_function(0) + >>> curve = BezierCurve([(1,1), (1,2)]) + >>> curve.bezier_curve_function(0) (1.0, 1.0) - >>> curve1.bezier_curve_function(1) + >>> curve.bezier_curve_function(1) (1.0, 2.0) """ - assert 0 <= t <= 1 # t must be between 0 and 1. + assert 0 <= t <= 1, "Time t must be between 0 and 1." basis_function = self.basis_function(t) x = 0.0 y = 0.0 for i in range(len(self.list_of_points)): - # summing up the product of i-th basis function and i-th point, for all points. + # For all points, sum up the product of i-th basis function and i-th point. x += basis_function[i] * self.list_of_points[i][0] y += basis_function[i] * self.list_of_points[i][1] - return (x, y) def plot_curve(self, step_size: float = 0.01): """ - plots the bezier curve using matplotlib plotting function. - step_size: defines the step(s) at which to evaluate the bezier curve and plot. + Plots the Bezier curve using matplotlib plotting capabilities. + step_size: defines the step(s) at which to evaluate the Bezier curve. The smaller the step size, the finer the curve produced. """ import matplotlib.pyplot as plt @@ -90,7 +83,7 @@ def plot_curve(self, step_size: float = 0.01): to_plot_x: List[float] = [] # x coordinates of points to plot to_plot_y: List[float] = [] # y coordinates of points to plot - t = 0 + t = 0.0 while t <= 1: value = self.bezier_curve_function(t) to_plot_x.append(value[0]) @@ -117,7 +110,5 @@ def plot_curve(self, step_size: float = 0.01): doctest.testmod() BezierCurve([(1, 2), (3, 5)]).plot_curve() # degree 1 - BezierCurve([(0, 0), (5, 5), (5, 0)]).plot_curve() # degree 2 - BezierCurve([(0, 0), (5, 5), (5, 0), (2.5, -2.5)]).plot_curve() # degree 3 From d8ef479f2a54a8bf4b8f23d9edf96e7168b68b2d Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Sat, 25 Jan 2020 07:17:35 +0100 Subject: [PATCH 7/7] Update bezier_curve.py --- graphics/bezier_curve.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/graphics/bezier_curve.py b/graphics/bezier_curve.py index 211da71a4737..512efadf86ee 100644 --- a/graphics/bezier_curve.py +++ b/graphics/bezier_curve.py @@ -7,9 +7,9 @@ class BezierCurve: """ - Bezier curve is a weighted sum of the control points. + Bezier curve is a weighted sum of a set of control points. Generate Bezier curves from a given set of control points. - The implementation works only for 2d points in the xy plane. + This implementation works only for 2d coordinates in the xy plane. """ def __init__(self, list_of_points: List[Tuple[float, float]]):