双三次Bezier曲面
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
实验六 双三次Bezier 曲面
一、实验目的
根据Bizer 曲面的基础知识和数学基础,对其算法进行程序设计,验证算法的正确性,并通过程序结果加深对常用曲面数学模型的理解。
二、实验任务(2学时)
Bezier 曲面算法及其程序设计。
三、实验内容和实验步骤
1、算法描述
Bezier 曲面是由Bezier 曲线拓广而来,以两组正交的Bezier 曲线控制点构造空间网格来生成曲面。
m×n 次张量积形式的 Bezier 曲面的定义如下(参照教材P200式7-20):
(u ,v )∈〔0,1〕×〔0,1〕
双三次Bezier 曲面定义如下(参照教材P201式7-21): (u ,v )∈〔0,1〕×〔0,1〕
展开上式,有
代入得到:
)()(),(m 0i ,,0
,∑∑
===v B u B P v u p n j m i n j j i 33
,,3,3i 00
(,)()() i j i j j p u v P B u B v ===∑∑
0,30,00,10,20,31,31,01,11,21,30,31,32,33,32,02,12,22,32,33,03,13,23,33,3()()(,)()()()()()()B v P P P P B v P P P P p u v B u B u B u B u P P P P B v P P P P B v ⎡⎤
⎡⎤⎢⎥⎢⎥⎢⎥⎢⎥⎡⎤=⋅⋅⎣⎦⎢⎥⎢⎥⎢
⎥⎢⎥⎢⎥⎣⎦⎣⎦
320,332
1,3
322,333,3()331()363()33()B u u u u B u u u u B u u u B u u ⎧=-+-+⎪=-+⎪⎨=-+⎪⎪=⎩320,3321,332
2,333,3
()331()363()33()B v v v v B v v v v B v v v
B v v ⎧=-+-+⎪=-+⎪⎨=-+⎪⎪=⎩0,00,10,20,31,01,11,21,3322,02,12,22,313313630(,)13
300P P P P P P P P p u v u u u P P P P --⎡⎤⎡⎤⎢⎥⎢⎥-⎢⎥⎢⎥⎡⎤=⋅⋅⎣
⎦⎢⎥⎢⎥-⎢⎥⎢⎥321331363033
00v v v ⎡⎤
--⎡⎤⎢⎥⎢⎥-⎢⎥⎢
⎥⋅⎢⎥
⎢⎥-⎢⎥⎢⎥
令
则有: 生成曲面时可以通过先固定u, 变化v 得到一簇Bezier 曲线;然后固定v ,变化u 得到另一簇Bezier 曲线,两簇曲线交织生成Bezier 曲面。
2、要求:
根据给定的16个控制顶点:
P00(200,20,0),P01(150,0,100),P02(50,-130,100),P03(0,-250,50); P10(150,100,100),P11(100,30,100),P12(50,-40,100),P13(0,-110,100); P20(140,280,90),P21(80,110,120),P22(30,30,130),P23(-50,-100,150); P30(150,350,30),P31(50,200,150),P32(0,50,200),P33(-70,0,100); 使用斜等测投影绘制双三次Bizer 网格曲面。
3、程序实现步骤:(工程名:BezierCurve2)
步骤1:创建“BezierCurve2”工程文件;
步骤2:创建类class :“ P2”及“P3”;注意:P2 为二维点,含有两个成员变量“x,y”,P3含有三个成员变量“x,y ,z”。
单击右键-“new class”-选择类型“Generic Class”名称为“ P2”及“P3”,添加成员变量(添加至“class EACH_ENTRY { public:”之内):
class P2 {
public: P2();
virtual ~P2(); double x; double y; };
class P3 {
public: P3();
321U u u u ⎡⎤=⎣⎦32
1V v v v ⎡⎤=⎣⎦1331363033001000be M --⎡⎤⎢⎥-⎢
⎥=⎢⎥-⎢⎥⎣⎦0,00,10,20,31,01,11,21,32,02,12,22,33,0
3,13,23,3P P P P P P P P P P P P P P P P P ⎡⎤⎢⎥⎢⎥=⎢⎥⎢⎥⎣⎦(,)T T
be be p u v UM PM V
=
virtual ~P3();
double x;
double y;
double z;
};
步骤3:包含头文件并定义顶点对象。
1)在“class CBezierCurve2View : public Cview……”之前添加代码“#include "P3.h"”及“#include "P2.h"”;
#include "P3.h"//包含三维坐标点类
#include "P2.h"//包含二维坐标点类
2)在“class CBezierCurve2View : public CView……”内添加代码:
P3 P3[4][4];//三维顶点
P2 P2[4][4];//二维顶点
步骤4:添加成员函数。
1)C m n的函数实现,定义成员函数,命名为Multiply_n。
方法及过程参照“实验六曲线及曲面生成算法(一)”;
2)伯恩斯坦多项式B m,n(t)的函数实现,添加CBezierCurve2View::bernstein。
方法及过程参照“实验六曲线及曲面生成算法(一)”;
步骤5:在OnDraw()中添加代码:
注意:添加头文件
#include "math.h"//数学头文件
#define Round(d) int(floor(d+0.5))//四舍五入宏定义
上述两行代码添加至:类CBezierCurve2View的所有成员函数代码之前。
1)窗口坐标变换,设置客户区中心为原点
CBezierCurve2Doc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
CRect rect;//定义客户区矩形
GetClientRect(&rect);//获得客户区的大小
pDC->SetMapMode(MM_ANISOTROPIC);//pDC自定义坐标系
pDC->SetWindowExt(rect.Width(),rect.Height());//设置窗口范围
pDC->SetViewportExt(rect.Width(),-rect.Height());//设置视区范围,x轴水平向右,y轴垂直向上
pDC->SetViewportOrg(rect.Width()/2,rect.Height()/2);//客户区中心为原点
rect.OffsetRect(-rect.Width()/2,-rect.Height()/2);
2)初始化16个控制顶点
P3[0][0].x=20; P3[0][0].y=0; P3[0][0].z=200;//P00
P3[0][1].x=0; P3[0][1].y=100;P3[0][1].z=150;//P01
P3[0][2].x=-130;P3[0][2].y=100;P3[0][2].z=50; //P02
P3[0][3].x=-250;P3[0][3].y=50; P3[0][3].z=0; //P03
P3[1][0].x=100; P3[1][0].y=100;P3[1][0].z=150;//P10
P3[1][1].x=30; P3[1][1].y=100;P3[1][1].z=100;//p11
P3[1][2].x=-40; P3[1][2].y=100;P3[1][2].z=50; //p12
P3[1][3].x=-110;P3[1][3].y=100;P3[1][3].z=0; //p13
P3[2][0].x=280; P3[2][0].y=90; P3[2][0].z=140;//P20
P3[2][1].x=110; P3[2][1].y=120;P3[2][1].z=80; //P21
P3[2][2].x=30; P3[2][2].y=130;P3[2][2].z=30; //P22
P3[2][3].x=-100;P3[2][3].y=150;P3[2][3].z=-50;//P23
P3[3][0].x=350; P3[3][0].y=30; P3[3][0].z=150;//P30
P3[3][1].x=200; P3[3][1].y=150;P3[3][1].z=50; //P31
P3[3][2].x=50; P3[3][2].y=200;P3[3][2].z=0; //P32
P3[3][3].x=0; P3[3][3].y=100;P3[3][3].z=-70;//P33
3) 三维控制顶点投影(采用斜等测法)至二维点:
for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
{
P2[i][j].x=P3[i][j].x-P3[i][j].z/sqrt(2);
P2[i][j].y=P3[i][j].y-P3[i][j].z/sqrt(2);
}
// 以上代码实现:从三维到二维的斜等测投影(参照教材P173:式6-42)
4)绘制控制多边形
CPen NewPen,*pOldPen;
NewPen.CreatePen(PS_SOLID,3,RGB(0,0,0));
pOldPen=pDC->SelectObject(&NewPen);
for(int i1=0;i1<4;i1++)
{
pDC->MoveTo(Round(P2[i1][0].x),Round(P2[i1][0].y));
for(int j1=1;j1<4;j1++)
pDC->LineTo(Round(P2[i1][j1].x),Round(P2[i1][j1].y));
}
for(int j2=0;j2<4;j2++)
{
pDC->MoveTo(Round(P2[0][j2].x),Round(P2[0][j2].y));
for(int i2=1;i2<4;i2++)
pDC->LineTo(Round(P2[i2][j2].x),Round(P2[i2][j2].y));
}
pDC->SelectObject(pOldPen);
NewPen.DeleteObject();
// 以上代码绘制控制多边形
5)控制顶点标注序号
CString str;
pDC->SetTextColor(RGB(0,0,255));
for(int i3=0;i3<4;i3++)
{
for(int j3=0;j3<4;j3++)
{
str.Format("P%d,%d",i3,j3);
pDC->TextOut(Round(P2[i3][j3].x+10),Round(P2[i3][j3].y+2),str);
}
}
// 以上代码实现“控制顶点标注序号”
6)“曲面”生成
CPen PenRed(PS_SOLID,1,RGB(255,0,0));//定义红色笔
pDC->SelectObject(&PenRed);//选择红色笔绘制曲面
double dt1=0.01,dt2=0.01;
double x,y,u,v;
double BU03,BU13,BU23,BU33;
double BV03,BV13,BV23,BV33;//U,V两个方向,三次曲面,共8个基函数
for(u=0;u<=1;u=u+dt1)
for(v=0;v<=1;v=v+dt2)
//对每一个u,v从0~1循环1/dt2+1次后,
//生成一条由1/dt2+1个点用直线串起来的“曲线”
//u从0~1循环1/dt2+1次后,生成1/dt1+1条“曲线”
{
BU03 = bernstein(0,3,u);//计算B0,3(u)
BV03 = bernstein(0,3,v);//计算B0,3(v)
BU13 = bernstein(1,3,u);//计算B1,3(u)
BV13 = bernstein(1,3,v);//计算B1,3(v)
BU23 = bernstein(2,3,u);//计算B2,3(u)
BV23 = bernstein(2,3,v);//计算B2,3(v)
BU33 = bernstein(3,3,u);//计算B3,3(u)
BV33 = bernstein(3,3,v);//计算B3,3(v)
//严格按照教材P201页,式7-21,为了简单起见,没有使用复杂的循环
x=(BU03*P2[0][0].x+BU13*P2[1][0].x+BU23*P2[2][0].x+BU33*P2[3][0].x)*BV03+ (BU03*P2[0][1].x+BU13*P2[1][1].x+BU23*P2[2][1].x+BU33*P2[3][1].x)*BV13+
(BU03*P2[0][2].x+BU13*P2[1][2].x+BU23*P2[2][2].x+BU33*P2[3][2].x)*BV23+ (BU03*P2[0][3].x+BU13*P2[1][3].x+BU23*P2[2][3].x+BU33*P2[3][3].x)*BV33;
y=(BU03*P2[0][0].y+BU13*P2[1][0].y+BU23*P2[2][0].y+BU33*P2[3][0].y)*BV03+ (BU03*P2[0][1].x+BU13*P2[1][1].y+BU23*P2[2][1].y+BU33*P2[3][1].y)*BV13+
(BU03*P2[0][2].y+BU13*P2[1][2].y+BU23*P2[2][2].y+BU33*P2[3][2].y)*BV23+
(BU03*P2[0][3].y+BU13*P2[1][3].y+BU23*P2[2][3].y+BU33*P2[3][3].y)*BV33;
if(v==0)
pDC->MoveTo(Round(x),Round(y));
else
pDC->LineTo(Round(x),Round(y));
}
//以上双重循环程序u=0、u=dt、u=2dt……u=1的共1/dt+1条“纵向”曲线段
for(v=0;v<=1;v=v+dt2)
for(u=0;u<=1;u=u+dt1)
{
BU03 = bernstein(0,3,u);
BV03 = bernstein(0,3,v);
BU13 = bernstein(1,3,u);
BV13 = bernstein(1,3,v);
BU23 = bernstein(2,3,u);
BV23 = bernstein(2,3,v);
BU33 = bernstein(3,3,u);
BV33 = bernstein(3,3,v);
x=(BU03*P2[0][0].x+BU13*P2[1][0].x+BU23*P2[2][0].x+BU33*P2[3][0].x)*BV03+
(BU03*P2[0][1].x+BU13*P2[1][1].x+BU23*P2[2][1].x+BU33*P2[3][1].x)*BV13+
(BU03*P2[0][2].x+BU13*P2[1][2].x+BU23*P2[2][2].x+BU33*P2[3][2].x)*BV23+
(BU03*P2[0][3].x+BU13*P2[1][3].x+BU23*P2[2][3].x+BU33*P2[3][3].x)*BV33;
y=(BU03*P2[0][0].y+BU13*P2[1][0].y+BU23*P2[2][0].y+BU33*P2[3][0].y)*BV03+
(BU03*P2[0][1].x+BU13*P2[1][1].y+BU23*P2[2][1].y+BU33*P2[3][1].y)*BV13+
(BU03*P2[0][2].y+BU13*P2[1][2].y+BU23*P2[2][2].y+BU33*P2[3][2].y)*BV23+
(BU03*P2[0][3].y+BU13*P2[1][3].y+BU23*P2[2][3].y+BU33*P2[3][3].y)*BV33;
if(u==0)
pDC->MoveTo(Round(x),Round(y));
else
pDC->LineTo(Round(x),Round(y));
}//此双重循环程序v=0、v=dt、v=2dt……v=1的共1/dt+1条“横向”曲线段//上述两批“纵向”及“横向”曲线段,犹如“织布”般“纵横交错”,dt取值越小,“布”越密实。
(3)编译、运行后查看结果,如图1所示。
图1 双三次Bezier曲面程序结果
四、总结和思考
1.查看实验结果,验证算法的正确性;
2.在程序中,修改参数dt(包括dt1和dt2)的增量值,分别取“0.001”、“0.02”、“0.04”及“0.1”,观察并分析结果。
3.修改相关参数,增加顶点数目分别至5*5个或更多。
考虑如何修改程序,并查看实验结果;
(注:可编辑下载,若有不当之处,请指正,谢谢!)。