计算机图形学bezier
bezier曲线

Bezier 曲线什么是 Bezier 曲线?Bezier 曲线是一种数学曲线,由法国工程师 Pierre Bézier 于20世纪50年代发明。
它是计算机图形学中最基本和最常用的曲线之一。
由于其简单性和灵活性,Bezier 曲线被广泛应用于计算机图形、工业设计、动画制作等领域。
Bezier 曲线的特点Bezier 曲线由一系列控制点确定,并通过调整这些控制点的位置和参数来定义曲线的形状。
以下是 Bezier 曲线的一些特点:1.可调节性:调整控制点的位置和参数可以改变曲线的形状、弯曲程度和速度。
2.平滑性:Bezier 曲线能够平滑连接控制点,使得曲线在控制点之间呈连续曲率。
3.参数化形状:Bezier 曲线可以通过调整参数来生成无限多种形状,从简单的直线到复杂的曲线。
4.逼近性:Bezier 曲线可以用来逼近其他复杂的曲线,如圆弧、椭圆等。
Bezier 曲线的数学表达Bezier 曲线是通过插值和多项式生成的数学曲线。
根据控制点的个数,可以确定 Bezier 曲线的阶数。
一般情况下,Bezier 曲线的阶数等于控制点数减1。
对于一维的 Bezier 曲线,它可由以下公式表示:Bezier 1DBezier 1D其中,n 为阶数,t 为参数,Pi 为控制点,Bi, n(t) 为 Bezier 基函数。
对于二维的 Bezier 曲线,它可由以下公式表示:Bezier 2DBezier 2D其中,n 为阶数,t 为参数,Pi 为控制点,Bi, n(t) 为 Bezier 基函数。
Bezier 曲线的应用Bezier 曲线的应用非常广泛,以下是一些常见的应用场景:1.计算机图形学:Bezier 曲线可以用来绘制平滑的曲线和曲面,用于构建2D和3D图形。
2.工业设计:Bezier 曲线可以用来设计平滑的汽车车身、家具等产品。
3.动画制作:Bezier 曲线可以用来定义动画路径,使得动画流畅而自然。
cubic bezier 计算公式

cubic bezier 计算公式Cubic Bezier计算公式Cubic Bezier曲线是一种常用的插值曲线,在计算机图形学和动画中被广泛应用。
它由四个点定义,包括两个端点和两个控制点。
根据这四个点的位置关系,可以计算出Cubic Bezier曲线上的任意点坐标。
下面我们将介绍Cubic Bezier计算公式的原理和应用。
Cubic Bezier曲线的计算公式如下:B(t) = (1-t)^3 * P0 + 3(1-t)^2 * t * P1 + 3(1-t) * t^2 * P2 + t^3 * P3其中,B(t)表示曲线上的点坐标,t表示参数值,范围为[0,1],P0、P1、P2和P3分别表示四个控制点的坐标。
通过调整这四个控制点的位置,可以得到不同形状的曲线。
Cubic Bezier曲线的计算公式是基于三次多项式的计算方法,通过对t的不同取值进行插值计算,得到曲线上的点坐标。
当t=0时,曲线上的点为P0;当t=1时,曲线上的点为P3。
通过调整t的取值范围,可以确定曲线的起点和终点。
Cubic Bezier曲线的计算公式可以通过矩阵运算的方式进行优化。
可以将四个控制点的坐标表示为一个矩阵,将参数t表示为一个列向量,通过矩阵乘法运算得到曲线上的点坐标。
这样可以提高计算效率,并简化代码实现。
Cubic Bezier曲线的计算公式有很多应用,其中最常见的应用是在图形设计和动画制作中。
通过调整四个控制点的位置,可以创建出各种形状的曲线,如圆弧、抛物线、S曲线等。
这些曲线可以用于绘制图形、实现动画效果、控制物体运动轨迹等。
在计算机图形学中,Cubic Bezier曲线还被广泛应用于图像处理和模型设计。
通过将曲线上的点连接起来,可以生成平滑的曲线轮廓。
这对于绘制曲线图形、生成字体轮廓、建模曲面等都非常有用。
除了基本的Cubic Bezier曲线计算公式,还有一些衍生的公式和算法,如二次Bezier曲线、B样条曲线等。
计算机图形学--第十一讲 Bezier曲线

任课教师:李陶深教授tshli@任课教师:李陶深教授tshli@12 曲线的基本概念Bézier 曲线5曲线与曲面的概述 4 3 6 B 样条曲线NURBS 曲线 常用的曲面Bézier曲线是由法国雷诺汽车公司工程师的Pierre Bézier在1971年发明的一种构造样条曲线和曲面的方法, 用来进行雷诺汽车的车身设计, 现在Bézier曲线曲面广泛应用在计算机图形学中的外形设计, 以及字体表示中.◆Bé◆在折线的各顶点中,只有第一点和最后一点在曲线上且作为曲线的起始处和终止处,其他的点用于控制曲线的形状及阶次。
◆曲线的形状趋向于多边形折线的形状,要修改曲线,只要修改折线的各顶点就可以了。
多边形折线又称的控制多边形,其顶点称为控制点。
6.3 Bézier 曲线—曲线的定义Bézier 曲线是由一组控制顶点和Bernstein 基函数混合(blending)得到的曲线.()[],0(), 0,1n i i n i t B t t ==∈∑C P 其中, P i (i =0,1,…,n)称为控制顶点; 顺序连接控制顶点生成控制多边形.()()[],1,0,1n i i i i n n B t C t t t -=-∈为Bernstein 基函数.Bézier 曲线的次数, 就是Bernstein 基函数的次数; Bézier 曲线的阶数, 就是控制顶点的个数. 阶数为次数加1.6.3 Bézier曲线—定义(2)给定空间n+1个点的位置矢量P i(i=0,1,2,…,n),则n次Bézier曲线上各点坐标的插值公式定义为:B i,n(t)是n次Bernstein基函数P i构成该Bézier曲线的特征多边形6.3 Bézier曲线—曲线的定义(3)Bézier曲线曲线的形状趋于特征多边形的形状①正性②权性由二项式定理可知:③对称性: 若保持原全部顶点的位置不变, 只是把次序颠倒过来, 则新的Bézier曲线形状不变, 但方向相反。
Bezier曲线B样条曲线

5.1 曲线的参数表示
参数的含义: 时间,距离,角度,比例等等; 规范参数区间[0,1]:归一化; 矢量表示: 切矢量(导函数): 例:已知直线段的端点坐标: 段的参数表达式为:
,则此直线
相应的x,y坐标分量为:
' ' 1 p ( t ) [ x ( t ) y (t )] [3 1] 切矢量为:
(1 t ) Bi ,n 1 ( t ) tBi 1,n 1 ( t )
5.2 Bezier、B样条曲线的生成
性质6:导函数
i i t (1 t )ni 对参数t求导得: 因为将Bi ,n (t ) Cn
n! Bi, n ( t ) [ it i 1 (1 t )n i t i ( n i )(1 t )n i 1 ] i !( n i )! ( n 1)! n t i 1 (1 t )( n 1) ( i 1) ( i 1)![( n 1) ( i 1)]! ( n 1)! i 1 n t i (1 t )( n 1) i Cn 1 i ![( n 1) i ]! n[ Bi 1, n 1 ( t ) Bi , n 1 ( t )]
u1
Z
Y
0
p(u1)
u2
p( u2)
u
注:这里讨论的动点轨迹 是在三维空间中所表 示的曲线,平面轨迹 曲线只是一种特殊情 况
X
5.1 曲线的参数表示
向量P与时间t有关:P=P(t),就是说P是时间t的函数。用 坐标表示为 :
x x(t ) y y( t ) z z(t )
第5章 曲线与曲面的生成与计算
5.1 5.2 5.3 曲线的参数表示 Bezier、B样条曲线的生成 曲面的参数表示
课件 计算机图形学 贝塞尔曲线及B样条

二 B样条曲线的数学表达式 1 通常,给定m+n+1个顶点Pi(i=0,1,2,…,m+n”),
可以定义m十1段n次的参数曲线为:
n
Pi,n (t) Pik • Fk,n (t)
(0 t 1)
k 0
式中:
Fk,n(t)为n次B样条基函数,也叫B样条分段混合函数。 其形式为:
C Fk,n
(t)
n
p(t) pi Bi,n (t)
(0 t 1)
i0
p(t) (1 t)3 p0 3t(1 t)2 p1 3t 2 (1 t) p2 t3 p3
其中混合函数分别为:
B0,3 = 1- 3t + 3t2 - t3 =
B1,3 = 3t - 6t2 + 3t3 =
B2,3 = 3t2 - 3t3 =
(二 )起始点与终止点切矢量的方向 通过对基函数求导,可以证明起始点与终止点的 切矢量与第1和第n(最后)条边一致(走向一致)。
基函数的导数:
B'i,n
(t)
n! i!(n
i)!
t(i 1
t)ni
'
Bi ,n
(t)
n! i!(n
i)!
t(i 1
t)ni
n! i·ti(1 1 t)ni (n i)t(i 1 t)ni1 i!(n i)!
贝塞尔曲 线
起始点
终止点
五 贝塞尔曲线的数学表达式:
Bezier曲线的数学基础:在第1个和最后一个端点之间进行
插值的多项式混合函数(调和函数)
它可以参用数方程表示如下:
n
p(t) pi Bi,n (t)
(0 t 1)
计算机图形学第7讲贝塞尔曲线

并满足方程 Q"(0) 2P"(1) P'(1)。
我们将 、 Q"(0) P"(1) 和 P'(1) ,Q0 Pn 、 Q1 Q2 (Pn Pn1) 代入,并整理,
可以得到:
Q2
2
2
n 1
1
Pn
2 2
2
n
1
A([P(t)] A n Pi Bi,n (t) A[Pi ]Bi,n(t)
i0
即在仿射变换下,的形式不变。
计算机图形学
3.2.2 Bezier曲线的递推(de Casteljau)算法
计算Bezier曲线上的点,可用Bezier曲线方程,但使
用de Casteljau提出的递推算法则要简单的多。
n2
c.)二阶导矢 P(t) n(n 1) (Pi2 2Pi1 Pi )Bi,n2 (t) i0
当t=0时,P"(0) n(n 1)(P2 2P1 P0 )
当t=1时,P" (1) n(n 1)(Pn 2Pn1 Pn2 )
上式表明:2阶导矢只与相邻的3个顶点有关,事实上,
r阶导矢只与(r+1)个相邻点有关,与更远点无关。
(i 0,1,..., n)
即高一次的Bernstein基函数可由两个低一次的 Bernsteini t i (1 t)ni
(Cni 1
C i1 n1
)t
i
(1
t
)
ni
(1 t)Cni 1t i (1 t)(n1)i tCni11t i1(1 t)(n1)(i1)
计算机图形学
Bezier曲线的递推(de Casteljau)算法
P1
P11
Bezier曲线和样条曲线的生成算法

计算机图形学实验报告实验名称 Bezier曲线和样条曲线的生成算法评分实验日期年月日指导教师姓名专业班级学号一、实验目的1、复习Bezier曲线和B样条曲线的参数表示法。
2、编程实现用二次Bezier曲线绘制。
3、编程实现用三次Bezier曲线绘制和分段光滑Bezier曲线图形的绘制。
4、用三次B样条函数绘制曲线。
二、实验要求1、编程实现在屏幕上绘制出两次Bezie曲线的几何图形和特征多边形图形,对于直线和曲线设置不同的线形和颜色。
2、现在屏幕上绘制出三次Bezie曲线的几何图形和特征多边形图形,对于直线和曲线设置不同的线形和颜色。
1、编程实现用分段三次Bezier曲线绘制光滑Bezier曲线图形。
1、编程实现在屏幕上绘制出三次B样条函数绘制曲线。
2、编程实现在屏幕上绘制出光滑连接的三次B样条曲线。
三、关键算法及实现原理1、二次Bezier曲线的计算公式为:P(t)=(P0-2P1+P2)t2+(-2P0+2P1)t+P0X(t)=(X0-2X1+X2)t2+(-2X0+2X1)t+X0Y(t)=(Y0-2Y1+Y2)t2+(-2Y0+2Y1)t+Y0其中P0、P1、P2为三个已知的点,坐标分别为(X0、Y0)、(X1、Y1)、(X1、Y2)。
2、次Bezier曲线的计算公式为:P(t)=(-P0+3P1-3P2+P3)t3+(3P0-6P1+3P2)t2+(-3P0+3P1)t+P0X(t)= (-X0+3X1-3X2+X3)t3+(3X0-6X1+3X2)t2+(-3X0+3X1)t+X0Y(t)= (-Y0+3Y1-3Y2+Y3)t3+(3Y0-6Y1+3Y2)t2+(-3Y0+3Y1)t+Y0其中P0、P1、P2、P3为四个已知的点,坐标分别为(X0、Y0)、(X1、Y1)、(X1、Y2) 、(X3、Y3)。
3、三次B样条函数绘制曲线的计算公式为:P(t)=[(-P0+3P1-3P2+3P3)t3+(3P0-6P1+3P2)t2+(-3P0+3P2)t+(P0+4P1+P2)]/6X(t)=[(-X0+3X1-3X2+3X3)t3+(3X0-6X1+3X2)t2+(-3X0+3X2)t+(X0+4X1+X2)]/6Y(t)=[(-Y0+3Y1-3Y2+3Y3)t3+(3Y0-6Y1+3Y2)t2+(-3Y0+3Y2)t+(Y0+4Y1+Y2)]/6其中P0、P1、P2、P3为四个已知的点,坐标分别为(X0、Y0)、(X1、Y1)、(X1、Y2) 、(X3、Y3)。
计算机图形学实验报告-实验3Bezier曲线

计算机图形学实验报告班级计算机工硕班学号 2011220456姓名王泽晶实验三:Bezier 曲线实验目的:通过本次试验,学生可以掌握Bezier 曲线的求值、升阶算法及Bezier 曲线绘制方法。
实验内容:1. 绘制控制多边形(使用鼠标左键指定多边形顶点,右键结束),使用白色折线段表示。
2. 绘制Bezier 曲线,使用红色,线宽为2,在右键结束控制多边形顶点指定时即执行。
Bezier 曲线是一种广泛应用于外形设计的参数曲线,它通过对一些特定点的控制来控制曲线的形状,我们称这些点为控制顶点。
现在我们来给出Bezier 曲线的数学表达式。
在空间给定1n +个点012,,,,n P P P P ,称下列参数曲线为n 次Bezier 曲线:,0()(),01ni i n i P t P B tt ==≤≤∑ 其中,()i n B t 是Bernstein 基函数,其表达式为:,!()(1)!()!i n ii n n B t t t i n i -=--,接着我们讨论3次Bezier 曲线,我们也采用将表达式改写为矩阵形式的方法,我们得到:3303!()(1)!(3)!i i ii P t P t t i i -==--∑32230123(1)3(1)3(1)t P t t P t t P t P =-+-+-+01323232323331,363,33,P P t t t t t t t t t P P ⎡⎤⎢⎥⎢⎥⎡⎤=-+-+-+-+⎣⎦⎢⎥⎢⎥⎣⎦01322313313630,,,133001000P P t t t P P --⎡⎤⎡⎤⎢⎥⎢⎥-⎢⎥⎢⎥⎡⎤=⎣⎦⎢⎥⎢⎥-⎢⎥⎢⎥⎣⎦⎣⎦试验步骤:添加成员函数,编写成员数代码为public class Al_deCasteljau {public function Al_deCasteljau(){}// de Casteljau递推算法的实现public function recursion( ctrlPts:Array, k:int , i:int ,t:Number ):Point {if ( k==0 ) return ctrlPts[i];return addPoints(multiplyNumToPoint((1 - t),recursion(ctrlPts, k-1, i, t)), multiplyNumToPoint(t , recursion(ctrlPts, k-1, i+1, t)));}public function multiplyNumToPoint(n:Number,p:Point):Point{return new Point(p.x * n,p.y * n);}public function addPoints(p1:Point,p2:Point):Point{return new Point(p1.x + p2.x,p1.y + p2.y);}public function minusPoints(p1:Point,p2:Point):Point{return new Point(p1.x - p2.x,p1.y - p2.y);}public function algorithm_deCasteljau(t:Number, ctrlPts:Array ):Point{var size:int = ctrlPts.length;return recursion( ctrlPts, size-1, 0, t );}public function upgradePoints(ctrlPts:Array):Array{var size:int = ctrlPts.length;var newPts:Array = new Array();newPts[0] = ctrlPts[0]; // i = 0for ( var i:int =1; i<size; ++i ){var factor:Number = i / size;newPts[i] = addPoints(multiplyNumToPoint( factor , ctrlPts[i-1] ) , multiplyNumToPoint((1 - factor) , ctrlPts[i]));}newPts[size] = ctrlPts[ctrlPts.length-1]; // i = n+1return newPts;}public function downgradePoints(ctrlPts:Array):Array{var size:int = ctrlPts.length;var newPts:Array = new Array();newPts[0] = ctrlPts[0]; // i = 0for ( var i:int=1; i<size-1; ++i ){var factor:Number = 1.0 /(size-1 - i);newPts[i] = multiplyNumToPoint(factor,minusPoints(multiplyNumToPoint(size-1 , ctrlPts[i]), multiplyNumToPoint(i , newPts[i-1])));}return newPts;}}编译运行得到如下结果:。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
计算机图形学课程设计报告Bezier曲线的算法实现学号:201005070214姓名:赵凯学院:信息科学与技术学院指导教师:邓飞学校:成都理工大学一、选题的意义及目的:贝塞尔曲线就是这样的一条曲线,它是依据四个位置任意的点坐标绘制出的一条光滑曲线。
在历史上,研究贝塞尔曲线的人最初是按照已知曲线参数方程来确定四个点的思路设计出这种矢量曲线绘制法。
贝塞尔曲线的有趣之处更在于它的“皮筋效应”,也就是说,随着点有规律地移动,曲线将产生皮筋伸引一样的变换,带来视觉上的冲击。
1962年,法国数学家Pierre Bézier第一个研究了这种矢量绘制曲线的方法,并给出了详细的计算公式,因此按照这样的公式绘制出来的曲线就用他的姓氏来命名是为贝塞尔曲线。
由于用计算机画图大部分时间是操作鼠标来掌握线条的路径,与手绘的感觉和效果有很大的差别。
即使是一位精明的画师能轻松绘出各种图形,拿到鼠标想随心所欲的画图也不是一件容易的事。
这一点是计算机万万不能代替手工的工作,所以到目前为止人们只能颇感无奈。
使用贝塞尔工具画图很大程度上弥补了这一缺憾。
贝塞尔曲线贝塞尔曲线是计算机图形图像造型的基本工具,是图形造型运用得最多的基本线条之一。
它通过控制曲线上的四个点(起始点、终止点以及两个相互分离的中间点)来创造、编辑图形。
其中起重要作用的是位于曲线中央的控制线。
这条线是虚拟的,中间与贝塞尔曲线交叉,两端是控制端点。
移动两端的端点时贝塞尔曲线改变曲线的曲率(弯曲的程度);移动中间点(也就是移动虚拟的控制线)时,贝塞尔曲线在起始点和终止点锁定的情况下做均匀移动。
注意,贝塞尔曲线上的所有控制点、节点均可编辑。
这种“智能化”的矢量线条为艺术家提供了一种理想的图形编辑与创造的工具。
它的主要意义在于无论是直线或曲线都能在数学上予以描述。
通过本次课程设计使我们对贝塞尔曲线更加熟悉!二、方法原理及关键技术:(1)原理:贝塞尔曲线于1962年,由法国工程师皮埃尔·贝塞尔(Pierre Bézier)所广泛发表,他运用贝塞尔曲线来为汽车的主体进行设计。
贝塞尔曲线最初由 Paul de Casteljau 于1959年运用 de Casteljau 算法开发,以稳定数值的方法求出贝塞尔曲线。
线性贝塞尔曲线给定点 P0、P1,线性贝塞尔曲线只是一条两点之间的直线。
这条线由下式给出:且其等同于线性插值。
二次方贝塞尔曲线的路径由给定点 P0、P1、P2 的函数 B(t) 追踪:TrueType 字型就运用了以贝塞尔样条组成的二次贝塞尔曲线。
P0、P1、P2、P3 四个点在平面或在三维空间中定义了三次方贝塞尔曲线。
曲线起始于 P0 走向 P1,并从 P2 的方向来到 P3。
一般不会经过 P1 或 P2;这两个点只是在那里提供方向资讯。
P0 和 P1 之间的间距,决定了曲线在转而趋进 P3 之前,走向 P2 方向的“长度有多长”。
曲线的参数形式为:现代的成象系统,如 PostScript、Asymptote 和 Metafont,运用了以贝塞尔样条组成的三次贝塞尔曲线,用来描绘曲线轮廓。
一般化:P0、P1、…、Pn,其贝塞尔曲线即。
例如:。
如上公式可如下递归表达:用表示由点P0、P1、…、P n所决定的贝塞尔曲线。
则用平常话来说,阶贝塞尔曲线之间的插值。
一些关于参数曲线的术语,有即多项式又称作n阶的伯恩斯坦基底多项式,定义00 = 1。
点 P i 称作贝塞尔曲线的控制点。
多边形以带有线的贝塞尔点连接而成,起始于 P 0 并以 P n 终止,称作贝塞尔多边形(或控制多边形)。
贝塞尔多边形的凸包(convex hull )包含有贝塞尔曲线。
线性贝塞尔曲线函数中的 t 会经过由 P 0 至P 1 的 B(t ) 所描述的曲线。
例如当 t=0.25 时,B(t ) 即一条由点 P 0 至 P 1 路径的四分之一处。
就像由 0 至 1 的连续 t ,B(t ) 描述一条由 P 0 至 P 1 的直线。
为建构二次贝塞尔曲线,可以中介点 Q 0 和 Q 1 作为由 0 至 1 的 t :∙ 由 P 0 至 P 1 的连续点 Q 0,描述一条线性贝塞尔曲线。
∙ 由 P 1 至 P 2 的连续点 Q 1,描述一条线性贝塞尔曲线。
∙ 由 Q 0 至 Q 1 的连续点 B(t ),描述一条二次贝塞尔曲线。
∙为建构高阶曲线,便需要相应更多的中介点。
对于三次曲线,可由线性贝塞尔曲线描述的中介点 Q 0、Q 1、Q 2,和由二次曲线描述的点 R 0、R 1 所建构:对于四次曲线,可由线性贝塞尔曲线描述的中介点 Q 0、Q 1、Q 2、Q 3,由二次贝塞尔曲线描述的点 R 0、R 1、R 2,和由三次贝塞尔曲线描述的点 S 0、S 1 所建构:P(t)=(1-t)P 0+tP 1 , 。
矩阵表示为:P(t)=(1-t)2P 0+2t(1-t)P 1+t 2P 2, 。
矩阵表示为:P(t)=(1-t)3P 0+3t(1-t)2P 1+3t 2(1-t)P 2+t 3P 3 。
三次B 样条曲线的算法实现:从三次B 样条曲线的定义可知:当n=3时,Q i,3(t)=∑P i+l F l ,3(t)= P i F 0,3(t)+ P i+1 F 1,3(t)+ P i+2 F 2,3(t)+ P i+ 3 F 3,3(t)因为四个调和函数F 0,3(t)、F 1,3(t)、F 2,3(t)和F 3,3(t) 已知(参看公式7-5-3)因此只要给出四个控制点的位置矢量的坐标,当t 在[0,1]范围内取离散地取100个点时(dt=0.01),分别求出每一个曲线上点,相邻点用直线段连接起来,就可以得到相应的B 样条曲线。
设控制点的个数为PointNum ,要求PointNum ≥4,则可以生成(PointNum-3)段三次B 样条曲线。
其中第i 段三次B 样条曲线的代数形式为:Q i,3(t)x = P i x F 0,3(t)+ P (i+1) x F 1,3(t)+ P (i+2) x F 2,3(t)+ P (i+3) x F 3,3(t) Q i,3(t)y = P i y F 0,3(t)+ P (i+1) y F 1,3(t)+ P (i+2) y F 2,3(t)+ P (i+3) y F 3,3(t) 其中,i=1,2,…, PointNum-3 三、程序设计和实现:Bezier 曲线的C++语言算法描述如下: (1) BH_BSpline.cpp#include "stdafx.h"#include "BH_BSpline.h" #include <math.h>BH_BSpline::BH_BSpline(int Row, int Column, int uOrder, int vOrder, int utype, int vtype, int Precision, double* dpCtlPts) {iRow=Row;iColumn=Column;memset(dpControlPoints, 0, MAXCONTROLPOINTS*sizeof(double)); if ( dpCtlPts != NULL )l =03set_dpControlPoints(dpCtlPts);else{srand( (unsigned)time( NULL ) );int u, v;for (v = 0; v <= iColumn; v++){for (u = 0; u <= iRow; u++){if ( iRow == 0 )dpControlPoints[(v*(iRow+1)+u)*3+0] = -0.5;elsedpControlPoints[(v*(iRow+1)+u)*3+0] = (GLdouble)u/iRow-0.5;if ( iColumn == 0 )dpControlPoints[(v*(iRow+1)+u)*3+1] = -0.5 ;elsedpControlPoints[(v*(iRow+1)+u)*3+1] = (GLdouble)v/iColumn-0.5;dpControlPoints[(v*(iRow+1)+u)*3+2] = (GLdouble)4/(iRow+iColumn)*(rand()%2);}}}memset(dpKnotsU, 0, MAXKNOTS*sizeof(double));memset(dpKnotsV, 0, MAXKNOTS*sizeof(double));UType=utype;VType=vtype;iUOrder=uOrder;iVOrder=vOrder;update_dpKnots(U);update_dpKnots(V);iPrecision=Precision;bDrawControlPoints=false;bDrawDiffVector=false;bWireFrame=true;bTexture=false;bLight=false;f or ( int v = 0; v<MAXN; v++)for ( int u = 0; u<MAXN; u++)bControlPointsSelected[v][u] = false ;}void BH_BSpline::set_dpControlPoints(double* value){memcpy(dpControlPoints, value, (iRow+1)*(iColumn+1)*3*sizeof(double)); return;}void BH_BSpline::set_dpKnotsU(double* value){memcpy(dpKnotsU, value, (iRow+iUOrder+1)*sizeof(double));return;}void BH_BSpline::set_dpKnotsV(double* value){memcpy(dpKnotsV, value, (iColumn+iVOrder+1)*sizeof(double)); return;}double* BH_BSpline::get_dpKnotsU(){return dpKnotsU ;}double* BH_BSpline::get_dpKnotsV(){return dpKnotsV ;}const int BH_BSpline::get_iPrecision() const{return iPrecision;}void BH_BSpline::set_iPrecision(int value){iPrecision = value;return;}const int BH_BSpline::get_iRow() const{return iRow;}const int BH_BSpline::get_iColumn() const{return iColumn;}void BH_BSpline::set_iUOrder(int value){if ( value < 0 || value > iRow ){AfxMessageBox("阶次k必须大于等于0且小于等于n");return;}iUOrder = value ;update_dpKnots(U) ;return;}void BH_BSpline::set_iVOrder(int value){if ( value < 0 || value > iColumn ){AfxMessageBox("阶次k必须大于等于0且小于等于n");return;}iVOrder = value ;update_dpKnots(V) ;return;}void BH_BSpline::set_UType(int type){UType=type;update_dpKnots(U);}void BH_BSpline::set_VType(int type){VType=type;update_dpKnots(V);}const int BH_BSpline::get_UType() const{return UType;}const int BH_BSpline::get_VType() const{return VType;}const int BH_BSpline::get_iUOrder() const{return iUOrder;}const int BH_BSpline::get_iVOrder() const{return iVOrder;}void BH_BSpline::Draw(int mode){if ( mode == GL_SELECT && !bDrawControlPoints ) //选取模式return ;glDisable(GL_LIGHTING);glDisable(GL_BLEND);int u, v;if (bDrawControlPoints) //绘制控制网格{glPointSize(8.0f);int index=0;for ( v = 0; v<=iColumn; v++)for ( u = 0; u<=iRow; u++){if ( mode == GL_SELECT )glLoadName(v*MAXN+u);if ( bControlPointsSelected[v][u] )glColor3f(1.0, 0.0, 0.0);elseglColor3f(1.0, 1.0, 1.0);float x, y, z;x=dpControlPoints[(v*(iRow+1)+u)*3+0];y=dpControlPoints[(v*(iRow+1)+u)*3+1];z=dpControlPoints[(v*(iRow+1)+u)*3+2];glBegin(GL_POINTS);glVertex3f(x, y, z);glEnd();}if ( mode == GL_SELECT ) //选取模式return ;glLineWidth(2.0);for ( u = 0; u<=iRow; u++){glBegin(GL_LINE_STRIP);for ( v = 0; v<=iColumn; v++){glColor3f(0.0, (GLdouble)(u)/(iRow+1), 1.0-(GLdouble)(u)/(iRow+1));float x, y, z;x=dpControlPoints[(v*(iRow+1)+u)*3+0];y=dpControlPoints[(v*(iRow+1)+u)*3+1];z=dpControlPoints[(v*(iRow+1)+u)*3+2];glVertex3f(x, y, z);}glEnd();}for ( v = 0; v<=iColumn; v++){glBegin(GL_LINE_STRIP);for ( u = 0; u<=iRow; u++){glColor3f(0.0, (GLdouble)(u)/(iRow+1), 1.0-(GLdouble)(u)/(iRow+1));float x, y, z;x=dpControlPoints[(v*(iRow+1)+u)*3+0];y=dpControlPoints[(v*(iRow+1)+u)*3+1];z=dpControlPoints[(v*(iRow+1)+u)*3+2];glVertex3f(x, y, z);}glEnd();}}//End Draw Control Points Gridsdouble d1[MAXPRECISION][3], d2[MAXPRECISION][3]; //记录两个相邻等u线——ui, ui+1点的数据double dpCtrlPointsV[MAXN*3]; //记录等u线对应的控制点double dpDiffVectorCtrlPointsU[MAXN*3], dpDiffVectorU[MAXPRECISION][3], dpDiffVectorV[MAXPRECISION][3], dpNormal[MAXPRECISION][3];CVertex vertex;//由于浮点数存在累计误差,所以在此uv采用整型for( u=0; u<=iPrecision; u+=1){bool bDraw=true;for(int v=0; v<=iColumn; v++) //计算u/iPrecision处的控制点{vertex=get_Vertex(U, (double)u/iPrecision, (double*)(dpControlPoints+v*(iRow+1)*3));dpCtrlPointsV[v*3+0]=vertex.dX;dpCtrlPointsV[v*3+1]=vertex.dY;dpCtrlPointsV[v*3+2]=vertex.dZ;vertex=get_TangentVector(U,(double)u/iPrecision,(double*)(dpControlPoints+v*(iRow+1)*3));dpDiffVectorCtrlPointsU[v*3+0]=vertex.dX;dpDiffVectorCtrlPointsU[v*3+1]=vertex.dY;dpDiffVectorCtrlPointsU[v*3+2]=vertex.dZ;}glLineWidth(1.0);glColor3f(0, (GLdouble)u/(iPrecision), 1-(GLdouble)u/(iPrecision));glBegin(GL_LINE_STRIP);for(v=0; v<=iPrecision; v+=1) //计算顶点坐标{vertex=get_Vertex(V, (double)v/iPrecision, dpCtrlPointsV);if (u%2==0){d1[v][0]=vertex.dX;d1[v][1]=vertex.dY;d1[v][2]=vertex.dZ;}else{d2[v][0]=vertex.dX;d2[v][1]=vertex.dY;d2[v][2]=vertex.dZ;}if (bWireFrame) //绘制等u线glVertex3f(vertex.dX, vertex.dY, vertex.dZ);}glEnd();if ( u>0 && bWireFrame ) //绘制等v线{for (v=0; v<=iPrecision; v++){glBegin(GL_LINES);glVertex3f(d1[v][0], d1[v][1], d1[v][2]);glVertex3f(d2[v][0], d2[v][1], d2[v][2]);glEnd();}}//计算切矢double divider;for(v=0; v<=iPrecision; v+=1){//v向单位切氏vertex=get_TangentVector(V, (double)v/iPrecision, dpCtrlPointsV); divider=sqrt(vertex.dX*vertex.dX+vertex.dY*vertex.dY+vertex.dZ*vertex.dZ);dpDiffVectorV[v][0]=vertex.dX/divider;dpDiffVectorV[v][1]=vertex.dY/divider;dpDiffVectorV[v][2]=vertex.dZ/divider;//u向单位切氏vertex=get_Vertex(V, (double)v/iPrecision, dpDiffVectorCtrlPointsU); divider=sqrt(vertex.dX*vertex.dX+vertex.dY*vertex.dY+vertex.dZ*vertex.dZ);dpDiffVectorU[v][0]=vertex.dX/divider ;dpDiffVectorU[v][1]=vertex.dY/divider;dpDiffVectorU[v][2]=vertex.dZ/divider;//AxB=(AyBz-AzBy)i+(AzBx-AxBz)j+(AxBy-AyBz)k;dpNormal[v][0]=(dpDiffVectorV[v][1]*dpDiffVectorU[v][2]-dpDiffVectorV[v][2]*dpDif fVectorU[v][1]);dpNormal[v][1]=(dpDiffVectorV[v][2]*dpDiffVectorU[v][0]-dpDiffVectorV[v][0]*dpDif fVectorU[v][2]);dpNormal[v][2]=(dpDiffVectorV[v][0]*dpDiffVectorU[v][1]-dpDiffVectorV[v][1]*dpDif fVectorU[v][0]);divider=sqrt(dpNormal[v][0]*dpNormal[v][0]+dpNormal[v][1]*dpNormal[v][1]+dpNor mal[v][2]*dpNormal[v][2]);dpNormal[v][0]/=(divider);dpNormal[v][1]/=(divider);dpNormal[v][2]/=(divider);glLineWidth( 3.0 ) ;glColor3f(1, 1, 0);}if (u>0 && (!bWireFrame || bTexture) ){if(bLight) glEnable(GL_LIGHTING);if(bTexture) glEnable(GL_TEXTURE_2D);glColor3f(1.0, 0, 0);for (v=0; v<iPrecision; v++) //面填充模式{if (u%2==1){glBegin(GL_QUADS);glNormal3f(dpNormal[v][0], dpNormal[v][1], dpNormal[v][2]);if(bTexture) glTexCoord2f( (double)(u-1)/(iPrecision), (double)(v)/(iPrecision) );glVertex3f(d1[v][0], d1[v][1], d1[v][2]);if(bTexture) glTexCoord2f( (double)(u)/(iPrecision), (double)(v)/(iPrecision) );glVertex3f(d2[v][0], d2[v][1], d2[v][2]);if(bTexture) glTexCoord2f( (double)(u)/(iPrecision), (double)(v+1)/(iPrecision) );glVertex3f(d2[v+1][0], d2[v+1][1], d2[v+1][2]);if(bTexture) glTexCoord2f( (double)(u-1)/(iPrecision), (double)(v+1)/(iPrecision) );glVertex3f(d1[v+1][0], d1[v+1][1], d1[v+1][2]);glEnd();}else{glBegin(GL_QUADS);glNormal3f(dpNormal[v][0], dpNormal[v][1], dpNormal[v][2]);if(bTexture) glTexCoord2f( (double)(u-1)/(iPrecision), (double)(v)/(iPrecision) );glVertex3f(d2[v][0], d2[v][1], d2[v][2]);if(bTexture) glTexCoord2f( (double)(u)/(iPrecision), (double)(v)/(iPrecision) );glVertex3f(d1[v][0], d1[v][1], d1[v][2]);if(bTexture) glTexCoord2f( (double)(u)/(iPrecision), (double)(v+1)/(iPrecision) );glVertex3f(d1[v+1][0], d1[v+1][1], d1[v+1][2]);if(bTexture) glTexCoord2f( (double)(u-1)/(iPrecision), (double)(v+1)/(iPrecision) );glVertex3f(d2[v+1][0], d2[v+1][1], d2[v+1][2]);glEnd();}}glDisable(GL_LIGHTING);glDisable(GL_TEXTURE_2D);}for(v=0; v<=iPrecision; v+=20) //绘制切矢{if (u%20==0 && bDrawDiffVector){glColor3f(1, 0, 0); glBegin(GL_LINES);glVertex3f(d1[v][0], d1[v][1], d1[v][2]);glVertex3f(d1[v][0]+dpDiffVectorV[v][0]/10,d1[v][1]+dpDiffVectorV[v][1]/10, d1[v][2]+dpDiffVectorV[v][2]/10);glEnd();glColor3f(0, 1, 0); glBegin(GL_LINES);glVertex3f(d1[v][0], d1[v][1], d1[v][2]);glVertex3f(d1[v][0]+dpDiffVectorU[v][0]/10,d1[v][1]+dpDiffVectorU[v][1]/10, d1[v][2]+dpDiffVectorU[v][2]/10);glEnd();glColor3f(0, 0, 1); glBegin(GL_LINES);glVertex3f(d1[v][0], d1[v][1], d1[v][2]);glVertex3f(d1[v][0]+dpNormal[v][0]/10, d1[v][1]+dpNormal[v][1]/10, d1[v][2]+dpNormal[v][2]/10);glEnd();}}}}CVertex BH_BSpline::get_V ertex(int direction, double t, double* dpCtrlPoints) {double* knots;int iCtrlPoints, iOrder;CVertex vertex;double a[MAXORDER], d[MAXORDER*3];if ( direction == U ){knots = dpKnotsU ;iCtrlPoints = iRow ;iOrder = iUOrder ;}else if ( direction == V ){knots = dpKnotsV ;iCtrlPoints = iColumn ;iOrder = iVOrder ;}elsereturn vertex;int i;for ( i = iOrder; i <= iCtrlPoints + 1 ; i++) {if ( (t>=knots[i]) && (t<=knots[i+1]) ){break ;}}if ( i > ( iCtrlPoints + 1 ) ){return vertex ;}memcpy(d, dpCtrlPoints+(i-iOrder)*3, (iOrder+1)*3*sizeof(double) ) ;for ( int k=iOrder; k>=1; k-- ) //第k次迭代{for ( int j=0; j<k; j++ ) //第j个a,d{if ( knots[i+j+1]==knots[i+j+1-k] ) //规定0/0=0a[j]=0;elsea[j]=(t-knots[i+j+1-k])/(knots[i+j+1]-knots[i+j+1-k]) ;d[j*3+0] = (1-a[j])*d[j*3+0] + a[j]*d[(j+1)*3+0] ;d[j*3+1] = (1-a[j])*d[j*3+1] + a[j]*d[(j+1)*3+1] ;d[j*3+2] = (1-a[j])*d[j*3+2] + a[j]*d[(j+1)*3+2] ;}}vertex.dX=d[0];vertex.dY=d[1];vertex.dZ=d[2];return vertex;}CVertex BH_BSpline::get_TangentVector(int direction, double t, double* dpCtrlPoints, int iTanOrder){double* knots;int iCtrlPoints, iOrder;CVertex vertex;double a[MAXORDER], d[MAXORDER*3];if ( direction == U ){knots = dpKnotsU ;iCtrlPoints = iRow ;iOrder = iUOrder ;}else if ( direction == V ){knots = dpKnotsV ;iCtrlPoints = iColumn ;iOrder = iVOrder ;}elsereturn vertex ;int i;for ( i = iOrder; i <= iCtrlPoints + 1 ; i++){if ( (t>=knots[i]) && (t<=knots[i+1]) ){break ;}}if ( i > ( iCtrlPoints + 1 ) ){return vertex ;}memcpy(d, dpCtrlPoints+(i-iOrder)*3, (iOrder+1)*3*sizeof(double) ) ;for ( int l = 1 ; l <= iTanOrder ; l++ ){for ( int j = 0 ; j <= iOrder-l ; j++ ) //Djl中j=i-k至i-r; 这里为了方便,下标统一减去了i-k,所以为0至k-r{if ( knots[i+j+1]==knots[i+j+1-(iOrder-l+1)] ) //规定0/0=0{d[j*3+0] = 0; d[j*3+1] = 0; d[j*3+2] = 0;}else{d[j*3+0] = ( iOrder - l + 1 ) * ( d[(j+1)*3+0] - d[j*3+0] ) / ( knots[i+j+1] - knots[i+j+1-(iOrder-l+1)] ) ;d[j*3+1] = ( iOrder - l + 1 ) * ( d[(j+1)*3+1] - d[j*3+1] ) / ( knots[i+j+1] - knots[i+j+1-(iOrder-l+1)] ) ;d[j*3+2] = ( iOrder - l + 1 ) * ( d[(j+1)*3+2] - d[j*3+2] ) / ( knots[i+j+1] - knots[i+j+1-(iOrder-l+1)] ) ;}}}for ( int k=iOrder-iTanOrder; k>=1; k-- ) //第k次迭代{for ( int j=0; j<k; j++ ) //第j个a,d{if ( knots[i+j+1]==knots[i+j+1-k] ) //规定0/0=0a[j]=0;elsea[j]=(t-knots[i+j+1-k])/(knots[i+j+1]-knots[i+j+1-k]) ;d[j*3+0] = (1-a[j])*d[j*3+0] + a[j]*d[(j+1)*3+0] ;d[j*3+1] = (1-a[j])*d[j*3+1] + a[j]*d[(j+1)*3+1] ;d[j*3+2] = (1-a[j])*d[j*3+2] + a[j]*d[(j+1)*3+2] ;}}vertex.dX=d[0];vertex.dY=d[1];vertex.dZ=d[2];return vertex ;}bool BH_BSpline::Save(LPCTSTR path){FILE *stream=NULL;stream = fopen( path, "w" );if(stream==NULL)return false;fprintf( stream, "BH_BSPline_File.\n");fprintf( stream, "Row=%d, Column=%d\n", iRow, iColumn);for ( int v = 0; v<=iColumn; v++){for ( int u = 0; u<=iRow; u++){float x, y, z;x=dpControlPoints[(v*(iRow+1)+u)*3+0];y=dpControlPoints[(v*(iRow+1)+u)*3+1];z=dpControlPoints[(v*(iRow+1)+u)*3+2];fprintf( stream, "%f,\t%f,\t%f\n", x, y, z);}}int i;int iUKnotsNumber=iRow+iUOrder+1;fprintf(stream, "UKnotsNumber=%d, UOder=%d, Type=%d\n", iUKnotsNumber, iUOrder , UType);for ( i = 0; i <= iUKnotsNumber; i++){fprintf(stream, "%f\t", dpKnotsU[i]);}fprintf(stream, "\n");int iVKnotsNumber=iColumn+iVOrder+1;fprintf(stream, "VKnotsNumber=%d, VOder=%d, Type=%d\n", iVKnotsNumber, iVOrder ,VType);for ( i = 0; i <= iVKnotsNumber; i++){fprintf(stream, "%f\t", dpKnotsV[i]);}fprintf(stream, "\n");fprintf(stream, "Precision=%d\n", iPrecision);fclose( stream );return true;}bool BH_BSpline::Open(LPCTSTR path){FILE *stream=NULL;stream = fopen( path, "r" );if(stream==NULL)return false;char header[32];fscanf( stream, "%s\n", header);if ( memcmp( header, "BH_BSPline_File.\n", 16 ) != 0 ){AfxMessageBox("该文件非B样条数据文件。