1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > 【CAD算法】【计算机图形学】Bezier贝塞尔曲线生成程序(python/numpy实现)[1]

【CAD算法】【计算机图形学】Bezier贝塞尔曲线生成程序(python/numpy实现)[1]

时间:2024-03-22 15:51:36

相关推荐

【CAD算法】【计算机图形学】Bezier贝塞尔曲线生成程序(python/numpy实现)[1]

整个项目,从Bezier曲线的创建,到Coons Patch曲面的实现,再到网格的实现和优化,还有最后对表面的光顺,链接如下:

【CAD算法】【计算机图形学】Bezier贝塞尔曲线生成程序(python/numpy实现)[1]

【CAD算法】【计算机图形学】Coons Patch曲面生成程序(python/numpy实现)[2]

【CAD核心算法】基于Laplacian Smoothing的网格mesh优化算法(python实现)[3]

【CAD算法】【遗传算法】采用遗传算法优化Coons Patch曲面程序(python实现)[4]

【CAD算法】基于最速下降法(梯度下降)的最短路径实现(python实现)[5]

1.内容回顾

首先回顾一下,表示一个曲线,有两种方式,implicit表示法和参数表示法。

implicit表示法:通过XYZ坐标表示曲线。

优点:

CompactEasy to check if a point belongs to the curve

缺点:

Difficult for curve evaluationDifficult for partial curve definition

参数表示法:Represent the X, Y, Z coordinates as a function of a single parameter

优点:

Easy for curve evaluation.Convenient for partial curve definition.Many others such as easy for manipulation, intersection.

很明显,参数表示法在工程领域中被广泛运用。

参数表示法有6种,分别是:

Conic sectionsPolynomial CurvesHermite CurvesBezier CurvesB-SplinesNon-Uniform Rational B-Splines (NURBS)

Conic sections:适用于描述圆锥曲线(圆/椭圆/双曲线/抛物线)。

Polynomial Curves:P(u) = [x(u) y(u) z(u)]T = a0 + a1u + a2u2 + a3u3 (0<=u<=1),这种表示法不能直观地通过改变a0到a3的值预测到曲线形状,一般不被运用。

Hermite Curves:P(u) = f0(u)P0 + f1(u)P1 + f2(u)P0’+ f3(u)P1’ (0<=u<=1),通过确定一条曲线两端点的坐标和斜率来确定一条曲线的坐标。同样不能直观地通过两端点的信息确定曲线的形状。

B spine:也就是B样条曲线,这种表示法得到最广泛的运用,它克服了Bezier曲线某一个控制点坐标变换会整体上地影响曲线形状这个缺点。

Bezier Curves:通过n+1个控制点的坐标,得到曲线的坐标。它的定义如下:

一定要注意,参数u的取值范围只能在0-1之间,包括端点。根据公式可知,只要知道了bezier曲线的维度n,也就是控制点数减一,就能计算出每一项的blending function的值,分别和控制点坐标相乘再求和,就能得到Bezier曲线的表达式。一旦确定了一个u的值,自然能得到对应曲线的坐标。如果想通过pyplot画出来,可以通过采样的方式,用很多个点来描述这个曲线。

2.题目描述

现在开始我们的程序。问题如下,用户通过txt或者控制台输入一组坐标,该程序能自动计算出Bezier曲线并通过画图软件画出来。

其中,输入信息格式如下:

Line 1 m/* Bezier 曲线的数量 */Line 2 n1/* 第一条Bezier曲线有多少个控制点 */Line 3 0 or 1/*0意味着该曲线首尾闭合, 1代表着首尾不相连 */Line 4 第一个控制点坐标 /* 坐标之间通过“,”或空格分开 */Line 5 第二个控制点坐标...Line n1+3 第n个控制点坐标

可能这么描述还不是很清楚,举一个例子:

2 #一共需要绘制2条Bezier曲线4 #第一条曲线有4个控制点1 #第一条曲线首尾不相连1.50.4-3 #控制点的三维坐标1.7 -2.56 4.78 #控制点的三维坐标0 245.6 10#控制点的三维坐标000#控制点的三维坐标3 #第二条曲线有4个控制点0 #第二条曲线首尾相连35-6 #控制点的三维坐标-43.57#控制点的三维坐标1.5-5-10.5 #控制点的三维坐标

3.解决方案

3.1头文件引用和变量定义

import osimport numpy as npimport matplotlibimport matplotlib.pyplot as pltfrom mpl_toolkits.mplot3d import Axes3Dimport pandas as pdnp.set_printoptions(suppress = True)#database = []m = np.array([],dtype = np.uint8) # the number of bazier curvespointsNumber = np.array([],dtype = np.uint8) #for the ith curve, the points number of itclosedOrOpen = np.array([],dtype = np.uint8) #for the ith curve, 0 means it is open, 1 means it is closedpoint = np.array([],dtype = np.float64) #the control points for all the curves

解释一下,以上四个变量均采用array数据类型,方便在内存中存放很多数据点并可视化。

其中,m是Bezier曲线数量;pointsNumber依次存放着每一条Bezier曲线的控制点数;closedOrOpen依次存放着每一条Bezier曲线是闭合的还是开放的bool数据;point依次存放着每一条Bezier曲线的全部特征点数,配合pointsNumber[i]指针可以很快定位到每一条Bezier曲线的第一个控制点在point数组中的位置。

3.2实现从txt文件的读取

def inputFromText():global filepathfilepath = os.path.abspath('.') + "/" + raw_input("please input the file name(eg:data.txt):")with open (filepath) as data:line_zero = data.readline()line_zero_list = list(line_zero.split())global mm = np.array(line_zero_list, dtype=np.uint8)for i in range(m[0]): pointsNumber_str = data.readline()pointsNumber_list = list(pointsNumber_str.split())temp1 = np.array(pointsNumber_list,dtype=np.uint8)global pointsNumberpointsNumber = np.append(pointsNumber,temp1) # the number of control points of the ith Bezier curveclosedOrOpen_str = data.readline()closedOrOpen_list = list(closedOrOpen_str.split())temp2 = np.array(closedOrOpen_list,dtype=np.uint8)global closedOrOpenclosedOrOpen = np.append(closedOrOpen,temp2) #0 means the ith curve is closed, 1 means it is openglobal pointfor j in range(temp1[0]):#u += 1point_str = data.readline()point_list = list(point_str.split())temp3 = np.array(point_list,dtype=np.float64)point = np.append(point,temp3) # control points for the ith Bezier Curvepoint = np.reshape(point, (-1,3))

读取txt采用python内置的文件操作函数。为了便于理解,采用循环方式依次读取txt的每一行,代码中没有介绍过的变量都是中间变量。

3.3 实现从控制台读取数据并保存数据到txt

def inputFromKeyboard(): m_int = input("the number of Beziercurve:") #the number of Beziercurveglobal mm = np.array([m_int],dtype = np.uint8)filename = raw_input("please input filename:(example: data.txt):") #input can only read 1 word!with open(filename,mode="w") as file_txt:file_txt.write(str(m_int)+'\n') #change to string!!for i in range(m_int): pointsNumber_str = str(input("numbers of control points of the {}th Bezier curve:".format(i)))pointsNumber_list = list(pointsNumber_str.split())temp1 = np.array(pointsNumber_list,dtype=np.uint8)global pointsNumberpointsNumber = np.append(pointsNumber,temp1) # the number of control points of the ith Bezier curve#u += 1file_txt.write(pointsNumber_str + '\n')closedOrOpen_str = str(input("0 or 1: 0 means the ith curve is closed, 1 means it is open:")) #0 means the ith curve is closed, 1 means it is openclosedOrOpen_list = list(closedOrOpen_str.split())temp2 = np.array(closedOrOpen_list,dtype=np.uint8)global closedOrOpenclosedOrOpen = np.append(closedOrOpen,temp2) #0 means the ith curve is closed, 1 means it is openfile_txt.write(closedOrOpen_str + '\n')global pointfor j in range(temp1[0]):point_str = str(raw_input("the coordinates of control points for the {}th Bezier Curve (eg: '0 0 0'):".format(i))) # control points for the ith Bezier Curvepoint_list = list(point_str.split())temp3 = np.array(point_list,dtype=np.float64)point = np.append(point,temp3) # control points for the ith Bezier Curvefile_txt.write(point_str + '\n')

需要注意的是,保存到txt里的是string类型。

3.4实现Bezier曲线的核心程序

def drawCurve(closedOrOpen,pointsNumber,point,point_index):C = []n = pointsNumber - 1 # n is fewer in numbers than the total control points number. According to definition.point_show = np.array([],dtype=np.float64)for i in range(n+1):point_show = np.append(point_show,point[point_index + i]) if (closedOrOpen == 0): # if it is closed, means the oth and nth control points are the same.n += 1point_show = np.append(point_show,point[point_index])elif (closedOrOpen == 1):passpoint_show = point_show.reshape((-1,3))#根据Bizier曲线定义if ((n+1) % 2 == 0):for i in range((n+1) / 2):up = 1down = 1j = nwhile (j > i):up *= jj = j - 1j = n - iwhile (j > 0):down *= jj = j - 1C.append(up / down)elif ((n+1) % 2 == 1):for i in range(n / 2):up = 1down = 1j = nwhile (j > i):up *= jj = j - 1j = n - iwhile (j > 0):down *= jj = j - 1C.append(up / down)up = 1down = 1j = nwhile (j > n/2):up *= jj = j - 1j = n/2while (j > 0):down *= jj = j - 1C.append(up / down)if (n%2 == 1):for i in range(int((n+1)/2)):C.append(C[int(n/2-i)])if (n%2 == 0):for i in range(int((n+1)/2)):C.append(C[int(n/2-i-1)])print("C",C) f = np.array([],dtype=np.float64)u = 0fx = 0fy = 0 #not this place!!fz = 0#print(f_unit.shape)print("point_show\n",point_show)print("n+1",n+1)for j in range(100): fx = 0fy = 0 #do not forget return 0!fz = 0for i in range(n+1):#这一条语句和Bezier曲线的表达式对应上了fx += C[i] * u**i * (1-u)**(n-i) * point_show[i][0]fy += C[i] * u**i * (1-u)**(n-i) * point_show[i][1]fz += C[i] * u**i * (1-u)**(n-i) * point_show[i][2]list = []list.append(fx)list.append(fy) list.append(fz)array_list = np.array([list],dtype=np.float64) u += 0.01f = np.append(f,array_list)f_show = f.reshape((-1,3))print(f_show.shape)#print(f_show)#show the control lines!ax.plot(f_show[:,0],f_show[:,1],f_show[:,2],'b.',markersize=1,label='open bazier curve')#bezier曲线,把'b.'改为'-'可以得到连续的曲线ax.plot(point_show[:,0],point_show[:,1],point_show[:,2],'-',markersize=1, label='control line')#控制点的连线ax.plot(point_show[:,0],point_show[:,1],point_show[:,2],'r.',markersize=8, label='control points')#控制点print(point_show.shape[0])

注意,当closedOrOpen为0时,也就是说这是一条封闭的Bezier,那么需要在末尾再把这个曲线的第一个控制点push进array里, 这样就能首尾相连。

3.5 main()函数

inputType = input("Please choose data from text/0 or keyboard/1 ?:")#print(inputType.type())if ( inputType == 0): # not '0'!!inputFromText()#从txt获取数据elif ( inputType == 1):inputFromKeyboard()#从键盘获取数据point_index = 0fig = plt.figure()ax = fig.gca(projection='3d')for i in range(m[0]):#绘制m条Bezier曲线drawCurve(closedOrOpen[i],pointsNumber[i],point,point_index)point_index += pointsNumber[i]#获取每一条Bezier曲线第一个控制点在数组中的位置ax.legend()ax.set_xlabel('X')ax.set_ylabel('Y')ax.set_zlabel('Z')plt.show()

4.试验结果

这个结果是根据样例数据绘制,红色点为各个Bezier曲线的控制点,中间的点为Bezier曲线,如果在plt.plot()中增加"-"参数或者增加点数,j这条曲线就能更好看一些。

采用Ubuntu16.03进行调试,交互界面如上。下图为一个更加残暴的数据所绘制出来的图像。

所有代码的链接如下:/iwander-all/CAD.git

参考文献

K. TANG, Fundamental Theories and Algorithms of CAD/CAE/CAM

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。