计算机图形学教程课后习题参考答案
- 格式:docx
- 大小:205.00 KB
- 文档页数:34
计算机图形学教程课后习题参考答案
文档编制序号:[KKIDT-LLE0828-LLETD298-POI08]
第一章
1、试述计算机图形学研究的基本内容
答:见课本P5-6页的1.1.4节。
2、计算机图形学、图形处理与模式识别本质区别是什么请各举一例说明。
答:计算机图形学是研究根据给定的描述,用计算机生成相应的图形、图像,且所生成的图形、图像可以显示屏幕上、硬拷贝输出或作为数据集存在计算机中的学科。
计算机图形学研究的是从数据描述到图形生成的过程。
例如计算机动画制作。
图形处理是利用计算机对原来存在物体的映像进行分析处理,然后再现图像。
例如工业中的射线探伤。
模式识别是指计算机对图形信息进行识别和分析描述,是从图形(图像)到描述的表达过程。
例如邮件分捡设备扫描信件上手写的邮政编码,并将编码用图像复原成数字。
3、计算机图形学与CAD、CAM技术关系如何
答:见课本P4-5页的1.1.3节。
4、举3个例子说明计算机图形学的应用。
答:①事务管理中的交互绘图
应用图形学最多的领域之一是绘制事务管理中的各种图形。
通过从简明的形式呈现出数据的模型和趋势以增加对复杂现象的理解,并促使决策的制定。
②地理信息系统
地理信息系统是建立在地理图形基础上的信息管理系统。
利用计算机图形生成技术可以绘制地理的、地质的以及其它自然现象的高精度勘探、测量图形。
③计算机动画
用图形学的方法产生动画片,其形象逼真、生动,轻而易举地解决了人工绘图时难以解决的问题,大大提高了工作效率。
5、计算机绘图有哪些特点
答:见课本P8页的1.3.1节。
6、计算机生成图形的方法有哪些
答:计算机生成图形的方法有两种:矢量法和描点法。
①矢量法:在显示屏上先给定一系列坐标点,然后控制电子束在屏幕上按一定的顺序扫描,逐个“点亮”临近两点间的短矢量,从而得到一条近似的曲线。
尽管显示器产生的只是一些短直线的线段,但当直线段很短时,连成的曲线看起来还是光滑的。
②描点法:把显示屏幕分成有限个可发亮的离散点,每个离散点叫做一个像素,屏幕上由像素点组成的阵列称为光栅,曲线的绘制过程就是将该曲线在光栅上经过的那些像素点串接起来,使它们发亮,所显示的每一曲线都是由一定大小的像素点组成的。
当像素点具有多种颜色或多种灰度等级时,就可以显示彩色图形或具有不同灰度的图形。
7、当前计算机图形学研究的课题有哪些
答:见课本P10-11页的节。
8、简述三维图形生成和输出的流水线
答:见课本P13页1.5.6.节。
9、向量图形和点阵图形之间的区别有哪些
答:通过矢量法产生的图形称为矢量图形或者向量图形,用描点法产生的图形称为点阵图形。
向量图形区别点阵图形的特点在于描述图形几何形状的数学模型及依据此模型生成几何图形的计算机命令。
向量图形由各个基本图形构成,这就要求各个基本图形有各自独立的信息。
如果用点阵图形来表示一个向量图形,构成向量图形的某个基本图形
(如直线段、圆弧等)的所有点应有一个信息。
因此,在描述一个基本图形时,同时要描述其相应的信息。
向量图形最基本的优点是它本身是由精确的数据给出,所以可以充分利用各种输出图形设备的分辨率尽可能精确地输出图形。
也正因为如此,向量图形的尺寸可以任意变化而不损失图形显示的质量。
但是向量图形仅适合于描绘简单图形,而点阵图形可以描绘绚烂多彩的复杂图形。
10、什么是虚拟现实技术和可视化技术
答:虚拟现实技术:利用计算机生成一种模拟环境,通过多种传感器和设备使用户“投入”到该环境中,实现用户和该环境直接进行交互的技术。
例如模拟飞机驾驶舱。
可视化技术:通过对空间数据场构造中间几何因素,或用图形绘制技术在屏幕上产生二维图像。
例如分子模型构造。
第二章
1、计算机图形系统有什么特点有哪些主要功能
答:课本2.1.1的图2
2、计算机图形系统有哪几种各有什么特点
答:一种分类方法:交互式图形系统允许操作者以某种方式(对话方式或命令方式)来控制和操作图形生成过程,使得图形可以边生成、边显示、边修改,直至符合要求为止。
而被动式绘图系统,图形在生成过程中,操作者无法对图形进行实时操作和控制,不具备交互功能,只提供各种图形命令或图形程序库,通过编程获得所需图形。
另一种分类方法:见课本2.1.3节,分为脱机绘图系统、联机绘图系统和交互式绘图系统。
3、阴极射线管由哪些部分组成它们的功能分别是什么
答:CRT 由四部分组成:电子枪、聚焦系统、偏转系统和荧光屏,这四部分都在真空管内。
电子枪由灯丝、阴极和控制栅极组成。
灯丝加热阴极,阴极表面向外发射自由电子,控制栅控制自由电子是否向荧光屏发出,若允许电子通过,形成的电子流在到达屏幕的途中,被聚焦系统(电子透镜)聚焦成很窄的电子束,由偏转系统产生电子束的偏转电场(或磁场),使电子束左右、上下偏转,从而控制荧光屏上光点上下、左右运动,使得在指定时刻在屏幕指定位置上产生亮点。
4、光栅扫描显示器由哪些部分组成它们的功能分别是什么
答:见课本P21页图所展示的组成框图,其后有各部分的介绍及功能。
5、对于分辨率为1024*1024的光栅系统,若每一像素用8位和12位二进制来表示存储信息,各需多大光栅存储容量以及显存每一屏幕最多能显示多少颜色若R ,G ,B 灰度都占8位,其显示颜色的总数是多少
解:
1)每一像素用8位二进制来表示存储信息,所需容量为1024*1024*1=20
2(Byte )=1MB
彩色素:82=256(项)
2)若每一像素用12位二进制表示存储信息,所需容量为:1024*1024*=*202(Byte) = (由于显示卡的显存是按2的指数次倍增长的,因此所需显存为2M)
彩色素:122=4096( 项)
3)颜色总数:28*28*28=224
(种)
6、对于19英寸显示器,若X 和Y 两方向的分辨率相等,即1024*1024,那么每个像素点的直径是多少
解: 210244.25*19=(mm )或2102419=(英寸)
7、对于分辨率为1024×768的光栅系统,若调色板设置为真彩色32位,此时需要显示一个三维图形,各需要多大光栅存储容量以及显存
答:调色板为真彩色32位,即意味着像素值的位长为32
所需容量为1024*768*32/8*3=9MB 因此所需要的显存为16M
8、GKS有哪三种坐标系它们有什么不同试写出它们之间对应关系
答:GKS有3种不同的坐标系。
第一种是供应用程序使用的实际世界坐标系统(World Coordinate System,简称 WC);第二种是GKS内部使用的规范设备坐标系(Normalized Device Coordinate,简称NDC),它的取值范围为[0,1],这是一种既与设备无关也与应用无关的坐标系;第三种是各工作站物理设备使用的设备坐标系(Device Coordinate System,简称DC)。
GKS只支持二维对象的图形处理,因此上述3个坐标系都是二维坐标系。
详见课本图的描述。
9、GKS中输入设备有哪6种逻辑功能请各举出对应的物理设备。
答:见课本2.4.5.节。
10、当前主流的图形软件有哪些
答:见课本2.6.3节。
第三章
1、编写画一正方形程序,并在其中用不同的颜色画15个正方形,每一个都比前一个小。
#include“”
#include“”
void main()
{
int i,color=0,ls=0;
int j=700;
int gdriver=VGA;
int gmode=VGAHI;
initgraph(&gdriver,&gmode,””);
setbkcolor(15);
for(i=0;i<225;i=i+15, j=j-30)
{
setcolor(color);
bar(i,i,j,j);
color++;
ls++;
}
getch();
closegraph();
}
2、用不同的线形绘制题1中的图形
#include “”
#include “”
void main()
{
int i,color=1,ls=0;
int j=700;
int gdriver=VGA;
gmode=VGAHI;
initgraph(&gdriver,&gmode,””);
setbkcolor(15);
for(i=0;i<=225;i=i+15, j=j-30)
{
setcolor(color);
2. 根据DDA 画直线算法,遍一程序求(0,0)到(4,12)和(0,0,)到(12,4)
的直线
#include “”
#include “”
void DDA_Line(int x1,int y1,int x2,int y2)
{
float increx,increy,x,y,length;
int i;
if(abs(x2-x1)>abs(y2-y1))
length=abs(x2-x1);
else
length=abs(y2-y1);
increx=(x2-x1)/length;
increy=(y2-y1)/length;
x=x1;
y=y1;
for(i=1;i<=length;i++)
{
putpixel(x,y,1);
x=x+increx;
y=y+increy;
}
}
void main()
{
int driver=DETECT,mode=0;
initgraph(&driver,&mode,””);
int x1=0,y1=0,x2=4,y2=12;
int x3=12,y3=4;
DDA_Line(x1,y1,x2,y2);
DDA_Line(x1,y1,x3,y3);
getch();
}
3. 根据逐点比较法编一程序画一段圆弧,其圆心为(0,0),圆弧两点为A(5,0)、B(0,5)
方法1:顺4象限
#include ""
#include ""
#include ""
void ZDBJ_ARC(float x0,float y0,float x1,float y1,float x2,float y2);
void main()
{
int gdriver=CGA,mode=CGAC0;
initgraph(&gdriver,&mode," ");
ZDBJ_ARC(0,0,25,0,0,25);
getch();
closegraph();
}
void ZDBJ_ARC(float x0,float y0,float x1,float y1,float x2,float y2)
{
float f=,F;
float dx=1,dy=1;
while(abs(x1-x2)>1)
{
if(f>=0)
{
x1=x1-dx;
y1=y1;
putpixel(x1,y1,1);
f=f-2*dx*(x1-x0)+dx*dx;
}
else
{
x1=x1;
y1=y1+dy;
putpixel(x1,y1,1);
f=f+2*dy*(y1-y0)+dy*dy;
}
}
}
方法2:逆4象限
#include ""
#include ""
#include ""
void ZDBJ_ARC(float x0,float y0,float x1,float y1,float x2,float y2); void main()
{
int gdriver=CGA,mode=CGAC0;
initgraph(&gdriver,&mode," ");
ZDBJ_ARC(0,0,0,25,25,0);
getch();
closegraph();
}
void ZDBJ_ARC(float x0,float y0,float x1,float y1,float x2,float y2) {
float f=,F;
float dx=1,dy=1;
while(abs(y1-y2)>1)
{
if(f>0)
{
x1=x1;
y1=y1-dy;
putpixel(x1,y1,1);
f=f-2*dy*abs(y1-y0)+dy*dy;
}
else
{
x1=x1+dx;
y1=y1;
putpixel(x1,y1,1);
f=f+2*dx*abs(x1-x0)+dx*dx;
}
}
}
方法3:顺1象限
#include“”编一程序用角度DDA法画一圆
B
采用DDA
直线是否完全相同为什么能否扩充整数
点坐标值不是整数的情况。
答:不相同。
因为DDA算法总是选择△x或者△y中的较大者作为步进的方向,不失一般性,假设选择x方向,则x方向每前进一个像素点,y方向前进的像素点个数应该在[0, 1]区间,但是由于采用了(向上或者向下或者四舍五入)取整运算,必然会导致某些像素点偏在了真实直线的一侧。
而Bressenham算法每一步都会根据实际直线与网格的距离来决定下一个像素点的选择,因此所选像素点更加贴近于真实的直线。
可以扩充整数Bressenham算法使之能够处理当线段端点坐标值不是整数的情况。
6. 若采用Bresenham算法实现画圆,写出算法实现的具体流程(包括判别公式推导等等)。
答:给定圆心在原点,半径为R的圆,其方程为x2+y2=R2,构造函数F(x, y)= x2+y2-
R2,对于圆上的点,有F(x, y)=0;对于圆外的点,F(x, y)>0;而对于圆内的点,F(x, y)<0。
此处仅考虑如图所示的第一象限内x ∈⎣⎦
2/,0R 的1/8圆弧,此时中点Bresenham
x 方向上走一步,而y 方向上或减1
或减0Pu(x i +1, y i )
假设M F(x M , y M )<0,M 在圆内,这说明Pu )>0,M 在圆外,说明Pd 离圆弧更近;当F(x M , y M )=0,则约定取Pd 。
构造判别式d i =F(x M , y M )= F(x i +1, =(x i +1)2+2- R 2 (1) 当d i <0,取Pu(x i +1, y i ),计算下一步的的判别式 d i+1=F(x u , y u )= F(x i +2, = (x i +2)2+2- R 2= d i +2x i +3 所以沿正右方向,d i 的增量为2x i +3。
(2) 当d i ≥0,取Pd(x i +1, y i +1),计算下一步的的判别式 d i+1=F(x d , y d )= F(x i +2, = (x i +2)2+2- R 2= d i +2(x i -y i )+5
所以沿右下方向,d i 的增量为2(x i -y i )+5。
显然,所绘制圆弧段的第一个像素为P 0(0, R),因此判别式d 0的初始值为,可以令d ’=来摆脱小数运算,则判别式d i <0对应于d i <,由于d 始终是整数,d i <等价于d i <0。
7. 已知4个型值点(,),(,),(,),(,),求各段三次样条曲线。
Si (X )(i=1,2,3),设边界条件为抛物线端 解:m1=x2-x1=, m2=x3-x2=, m3=x4-x3=1; λ2=m2/(m2+m1)=;
u2=m1/(m1+m2)=; λ3=m3/(m2+m3)=; u3=m2/(m2+m3)=;
R2=3*[u2*(y3-y2)/m2+λ2*(y2-y1)/m1]=; R3=3*[u3*(y4-y3)/m3+λ3*(y3-y2)/m2]=;
, ,
,
,
Y
X 圆
于是有
+2b2+= (1)
+2b3+= (2)
又边界抛物线端
b1+b2=2 (3)
b3+b4=-1 (4)
由(1),(2),(3),(4)得
b1=39/38, b2=37/38, b3=3/38, b4=-41/38
从而
c1=-1/57;
d1=0;
c2=-1/57;
d2=-64/513;
c3=-11/19;
d3=0;
故可得
s1(x)=2+39/38(x-1)-1/57(x-1)2 x∈[, ]
s2(x)=+37/38-1/572-64/5133 x∈[, ]
s3(x)=+3/38(x-4)-11/19(x-4)2 x∈[, ]
8. 已知4个型值点坐标值P0(5,5)、P1(10,15)、P2(15,10)、P3(10,5),绘一个三次贝塞尔曲线。
解:
用矩阵表示为
p(t)=[t3 t2 t 1]P[p0 p1 p2 p3]T
P=
-1 3 -3 1
3 -6 3 0
-3 3 0 0
1 0 0 0
p=[, ]
p=[, ]
p=[, ]
p=[, ]
p=[, ]
p(1)=[10, 5]
将上面各点相连可以画出三次贝塞尔曲线。
9. 编写一个绘制Bezier曲线的程序。
该程序根据以下数据点[x, y]:[50, 100] [80, 230] [100, 270] [140, 160] [180, 50] [240, 65] [270, 120] [330, 230] [380, 230] [430, 150]计算出结果,并实现三段首尾相接的三次贝塞尔曲线在屏幕上显示的功能,采用了C++语言实现;
#include ""
#include ""
#include ""
typedef struct
{
double x,y;
} DPOINT; , bP[i].y, bP[i+1].x, bP[i+1].y ); , bP[i].y,5); ,bP[m_maxIndex].y,5);
}
void Bezier::drawCurve() +3*bP[p1].x-3*bP[p2].x+bP[p3].x)*t*t*t+(3*bP[p0].x-6*bP[p1].x+3*bP[p2].x)*t*t+(-3*bP[p0].x+3*bP[p1].x)*t+bP[p0].x; tmpy=(-bP[p0].y+3*bP[p1].y-
3*bP[p2].y+bP[p3].y)*t*t*t+(3*bP[p0].y-6*bP[p1].y+3*bP[p2].y)*t*t+(-3*bP[p0].y+3*bP[p1].y)*t+bP[p0].y;
putpixel(tmpx,tmpy,3);
}
}
void main() =;
p[0].y=;
p[1].x=;
p[1].y=;
p[2].x=;
p[2].y=;
p[3].x=;
p[3].y=;
p[4].x=;
p[4].y=;
p[5].x=;
p[5].y=;
p[6].x=;
p[6].y=;
p[7].x=;
p[7].y=;
p[8].x=;
p[8].y=;
p[9].x=;
p[9].y=;
Bezier bzr(p,10); (); delete p; getch(); closegraph();
}
10. 编写一个绘制B 样条曲线的程序。
该程序根据以下数据点[x, y]:P0[50, 130] P1[120, 40] P2[100, 270]和P3[140, 160]计算出结果,并实现两段首尾相接的两次B 样条曲线在屏幕上显示的功能,采用了C++语言实现;
将已知点代入式(4-19)可得两段两次B 样条曲线方程:
P 1(t )= 2
1[ t 2 t 1]⎢⎢⎢⎣⎡-12
1
122- ⎥⎥⎥⎦
⎤001⎢⎢⎢⎣⎡10012050
⎥⎥⎥⎦
⎤27040130 =[-45 160]t 2 +[70 -90]t +[85 85]
P 2(t )= 2
1[ t 2 t
1]⎢⎢⎢⎣⎡-121
122- ⎥⎥
⎥⎦
⎤001⎢⎢⎢⎣⎡140100120
⎥⎥⎥⎦
⎤60127040 = [30 -170]t 2 +[-20 230]t +[110 155]
#include "" #include "" #include "" typedef struct { double x,y;
} DPOINT; , bP[i].y, bP[i+1].x, bP[i+1].y ); , bP[i].y,5); ,bP[m_maxIndex-1].y,5);
}
void B_Spline::drawCurve() -bP[p1].x+*bP[p2].x)*t*t+(-bP[p0].x+bP[p1].x)*t+*bP[p0].x+*bP[p1].x;
tmpy=*bP[p0].y-bP[p1].y+*bP[p2].y)*t*t+(-bP[p0].y+bP[p1].y)*t+*bP[p0].y+*bP[p1].y;
putpixel(tmpx,tmpy,3);
}
}
void main() =; p[0].y=; p[1].x=;
p[1].y=;
p[2].x=; p[2].y=; p[3].x=; p[3].y=;
B_Spline b_sp(p,4); (); delete p; getch(); closegraph();
}
11. 简述NURBS 曲线产生的背景和特点
答:NURBS 曲线具有局部可调性、凸包性、几何和透视投影变换不变性等等,它采用有理参数多项式可以精确表示圆锥曲线、二次曲面等,对于几何造型算法提供了思路。
12. 将下列数据
X 2 6 10 12 14 16 Y 3 8 11 13 15 17
按最小二乘法曲线拟合,分别求一次和二次多项式曲线,拟合以上数据并画图表示。
解:如下表所示:
一次多项式的情形: 60a +601a =67 0a =
600a +7361a =802 1a = 所求多项式为y=f(x)=+
二次多项式的情形:
60a +601a +7362a =67 0a =
600a +7361a +97922a
1a = 736
0a +97921a +1360002
a =10564 2a =
所求多项式为y=f(x)=+ 设五边形的五个顶点坐标为(10, 10),(15, 5),(12, 5),(8, 2)和(4, 5),利用多边形区域填充算法,编一程序生成一个实心图。
解:假设以上五个顶点依次对应编号A-B-C-D-E ,首先计算得到ET 表:
0123456789100123
45678910111213141516
6-10 5 4 3 2 1
0 用于存放AET 活动边表 该多边形的AET 指针的内容为: 1 AET 为空
2 3
4 5
6 7 8 9 10
第1步:(1) 根据输入的五个顶点坐标找到y值最小的点(例如点D,此时y=2),并找到与D有边关系的两个顶点(此时为E和C),在y=2处建立ET边表记录(ymax、xi和m值均可通过顶点坐标间的计算得到,例如DE边的建立,特别注意:当D点和E点y坐标值相同时,也即是DE与x轴平行,该边不能计入ET边表),之后标记D点被访问过;
(2) 排除访问过的点以及和该点相关联的边,重复(1)直至将ET表建立完善。
[注]边关系的建立可通过邻接矩阵的数据结构实现,权值可以为该矩阵行编号对应点的y坐标值,ET边表采用邻接表的数据结构
第2步:根据ET表构建AET表,并逐行完成多边形填充,具体的C++代码如下:(1) 建立头文件,主要是边表结点结构体和ET边表类的实现
enum ResultCode{Success, Failure};
template <class T>
struct Enode
{
Enode() {next=NULL;}
Enode(T pymax, float pxi, float pm, Enode *pnext)
{
ymax=pymax; xi=pxi;
m=pm; next=pnext;
}
T ymax, xi; 已知多边形各顶点坐标为(2, 2)(2, 4)(8, 6)(12, 2)(8, 1)(6, 2)及(2, 2),在用多边形区域填充时,请写出ET及全部AET内容。
解:如图所示:
1234567891011120123456789101112
则该多边形的ET 表为: 6 5 4 3 2 1
1行表示将ET 表加入
AET 中,第2行表示从AET 表中删去y i =y max ,第3行表示x i =x
i +1/m 后,学生只要写出第2行即可) 1
2 3 P 4
4 5 6
15.
204060801001201401601802000
30
6090120150180210240270300
该测
试多边形的各个端点坐标分别为:
A(50, 150),B(50, 100),C(100, 50),D(250, 50),E(200, 150); F(100, 100),G(100, 75),H(175, 135);
/****************************************************************************
本程序实现区域填充功能,首先输入多边形顶点的个数,回车, 然后依次输入各顶点的坐标格式如下:100,123回车
一定要在中间用逗号隔开噢,输完最后一个点后,屏幕上会依次 画出各条边,最后填充满
程序还不完善,比如颜色值应该用变量表示以易于修改,画多边形和求种子点 应该做成独立的函数等等,以后再做上吧,这是细节的问题
扫描的次序:先上后下 进栈的次序:先右后左 测试数据:
第一个多边形:A(50, 150),B(50, 100),C(100, 50),D(250, 50),E(200, 150); 第二个多边形:F(100, 100),G(100, 75),H(175, 135);
*****************************************************************************/
#include <> #include <> #include <> #include <> #include <>
,(20, 15)和(0, 15),对此图形分别进行下列比例
(1) (2) 解:如图所示,实线部分为原图,虚线部分为变换后得到的图形: Y 30
(1)
⎥⎥⎥⎥⎦⎤⎢⎢⎢⎢⎣⎡1150115201020100*⎥⎥⎥⎦⎤⎢⎢⎢⎣⎡100020000.5=⎥⎥⎥⎥⎦
⎤
⎢⎢⎢⎢⎣⎡1300130101010100 (2) 原先坐标 变换矩阵 变换后坐标
⎥⎥⎥⎥⎦⎤⎢⎢⎢⎢⎣⎡1150115201020100*⎥⎥⎥⎦⎤⎢⎢⎢⎣⎡0.500010001=⎥⎥⎥⎥⎦⎤⎢⎢⎢⎢⎣⎡0.51500.515200.50200.500 归一化 ⎥⎥⎥⎥⎦
⎤⎢⎢⎢⎢⎣⎡1300130401040100 图(b)
17.已知三角形各顶点坐标为(10,10),(10,30),(30,15),试对其进行下列变换,写出变换矩阵,画出变换后的图形。
(1)沿X向平移20,沿Y向平移15,再绕原点旋转90度
(2)绕原点旋转,再沿X向平移20,沿Y轴平移15
解:(1)由二维图形变换相关知识,可得变换矩阵为
1 0 0 cos90 sin 90 0 0 1 0
0 1 0 -sin90 cos90 0 = -1 0 0
20 15 1 0 0 1 -15 20 1
根据得出的新坐标可画出图形(图形略)
新坐标的值为[-25, 30][-45, 30][-30, 50]
(2)变换矩阵为:
10 10 1 0 1 0
T= 10 30 1 -1 0 0
30 15 1 20 15 1
坐标数据点变换矩阵
10 25 1
T= -10 25 1
5 45 1
由得出的新坐标画图(图形略)
18.已知直线方程
(1)y=kx+b
(2)x/a+y/b=1(a!=!=0)
试求出图形对该直线进行对称变换得变换矩阵
解:(1)
kx-y+b=0
α=arctg(-A/B) =arctgk (1)
cos2α sin2α 0
T= sin2α -cos2α 0 (2)
(Cos2α-1)C/A sin2αC/A 1
将(1)代入(2)式可得变换矩阵,并根据万能公式
sin2α =2sin αcos α cos2α =cos 2α-sin 2α tg α =sin α/cos α 可得
(1-K 2)/(1+K 2) 2K/(1+K 2) 0
T= 2K/(1+K 2) (K 2-1)/(K 2+1) 0
-2bK/(1+K 2) 2b/(1+K 2) 1
(2)
x/a +y/b =1
bx+ay-ab=0
所以α=arctg(-A/B)=arctg(-b/a) (3)
将(3)代入(2)式得
(a 2-b 2)/(a 2+b 2) -2ab/(a 2+b 2) 0
T= -2ab/(a 2+b 2) (b 2-a 2)/(b 2+a 2) 0
2ab 2/(a 2+b 2) 2a 2b/(a 2+b 2) 1
19. 编一程序实现直线的编码裁剪法
解:具体源代码如下所示:
#include ""
#include ""
#include ""
#include ""
int w1=90, w2=270, w3=40, w4=160;
编一程序实现直线中点分割裁剪法
解:如图所示: #include "" #include "" #include "" #include ""
#define e 1 什么是反走样技术,比较超采样和区域采样的异同点
答:各种光栅化算法,如非水平亦非垂直的直线或多边形边界进行扫描转换时,或多或少会产生锯齿或阶梯状。
我们把这种用离散量表示连续量引起的失真称为走样
(xmax,
ymax)
(xmin, ymin) P1(x1,
y1)
(Aliasing)。
走样是数字化发展的必然产物。
所谓的反走样(Antialiasing)技术,就是减缓或者消除走样效果的技术。
目前有两类反走样的方法,第一类方法是通过提高采样频率(提高光栅分辨率)来显示图形的细节。
基于此,可以将显示器看成比实际更加细腻的网格,在这种假想的高分辨率上对光栅进行计算,采用某种平均算法得到较低分辨率的像素的属性,并把结果转换到较低分辨率的显示器上进行显示。
我们将这种方法称之为超采样(Supersampling)或者后置滤波(有些教材也称为过取样)。
第二类反走样技术是根据图形在每个像素点上的覆盖程度来确定像素点的最终亮度,此时将像素点当成了一个有面积的平面区域而并非一个点,这种方法称之为区域采样(Area Sampling)或者前置滤波。
第五章 习题参考答案
1.试编写一个绘制Bezier 曲面的程序。
解答:
void CMyView::OnAppBezier()
{
2222333cos θsin θsin θcos θ2
33
2221/32/3cos θ+1/33sin 1/3cos θθ+-
1/31/3cos θθ-1/31/32/3cos θ+1/33sin 1/3cos θθ-
1/33sin 1/3cos θθ-1/33sin 1/3cos θθ-1/32/3cos θ+1f246a186f266c/
int i, j, m, n;
float *pNewMatrix1, *pNewMatrix2, Sum;
if( Num_Column_Matrix1 != Num_Row_Matrix2) {
printf("Invalid Matrixs!\n");
return 0;
}
pNewMatrix1 = malloc(Num_Row_Matrix1 * Num_Column_Matrix2 * 4);
/*申请内存空间, Size(/bytes) = 第一个矩阵的行数 * 第二个矩阵的列数* 4(= sizeof(float))*/
pNewMatrix2 = pNewMatrix1;
/*具体算法详见如下代码*/
for( i = 0; i < Num_Row_Matrix1; i++) {
for( n = 0; n < Num_Column_Matrix2; n++) {
Sum = 0;
for( j = 0; j < Num_Column_Matrix1; j++)
Sum += (*(pMatrix1+i*Num_Column_Matrix1+j)) * (*(pMatrix2+j*Num_Column_Matrix2+n));
*(pNewMatrix1++) = Sum;
}
}
return pNewMatrix2;
}
/*转换成齐次坐标矩阵*/
void Matrix_Convertion(float *pMatrix, int Num_Row) {
int i, j;
for(i = 0; i < Num_Row; i++) {
if((*(pMatrix+i*4+3)) != 0) {
*(pMatrix+i*4) = (*(pMatrix+i*4)) / (*(pMatrix+i*4+3));
*(pMatrix+i*4+1) = (*(pMatrix+i*4+1)) /
(*(pMatrix+i*4+3));
*(pMatrix+i*4+2) = (*(pMatrix+i*4+2)) / (*(pMatrix+i*4+3));
}
}
}
/*取得投影坐标*/
float *Get_X_Y(float *pMatrix, int Num_Row) {
int i, j, Num;
float *pNewMatrix;
Num = 0;
for(i = 0; i < Num_Row; i++) {
if((*(pMatrix+i*4+3)) != 0)
Num++;
}
pNewMatrix = malloc(Num * 2 * 4);
/*存放格式,{(x1, y1),(x2, y2), ... ,(xn, yn)}*/
for(i = 0; i < Num; i++) {
if((*(pMatrix+i*4+3)) != 0) {
*(pNewMatrix+i*2) = (*(pMatrix+i*4))+300; /*显示在屏幕中心, x = 300*/
*(pNewMatrix+i*2+1) = (*(pMatrix+i*4+1))+200; /*显
示在屏幕中心, y = 200*/
}
}
return pNewMatrix;
}
/*设置旋转矩阵, Rotate around aixs labled with X or Y or Z*/ void SetMatrix_X(float X_Angle) {
float CosX, SinX;
SinX = sin(X_Angle * PI /128);
CosX = cos(X_Angle * PI /128);
X_Rotate_Matrix[1][1] = CosX;
X_Rotate_Matrix[1][2] = SinX;
X_Rotate_Matrix[2][1] = -1 * SinX;
X_Rotate_Matrix[2][2] = CosX;
}
void SetMatrix_Y(float Y_Angle) {
float CosY, SinY;
SinY = sin(Y_Angle * PI /128);
CosY = cos(Y_Angle * PI /128);
Y_Rotate_Matrix[0][0] = CosY;
Y_Rotate_Matrix[0][2] = -1 * SinY;
Y_Rotate_Matrix[2][0] = SinY;
Y_Rotate_Matrix[2][2] = CosY;
}
void SetMatrix_Z(float Z_Angle) {
float CosZ, SinZ;
SinZ = sin(Z_Angle * PI /128);
CosZ = cos(Z_Angle * PI /128);
Z_Rotate_Matrix[0][0] = CosZ;
Z_Rotate_Matrix[0][1] = SinZ;
Z_Rotate_Matrix[1][0] = -1 * SinZ;
Z_Rotate_Matrix[1][1] = CosZ;
}
/*类同*/
void Set_Transist_Matrix(float X, float Y,float Z) { Transist_Matrix[3][0] = X;
Transist_Matrix[3][1] = Y;
Transist_Matrix[3][2] = Z;
}
/*类同*/
void Set_Perspective_Projection(float k) {
Perspective_Projection[2][3] = -1/k;
}
/*初始化图形驱动*/
void InitGraph(void) {
int gd=DETECT,gm;
initgraph(&gd,&gm,"E:\\TC");
}
/*生成立方体*/
float *Cube(void) {
int i, j, k;
float *pPoints1, *pPoints2;
num = 0;
for( i = -50; i <= 50; i += 20)
for( j = -50; j <= 50; j += 20)
for( k = -50; k <= 50; k += 20) num++;
pPoints1 = malloc( num * 4 * 4 );
pPoints2 = pPoints1;
for( i = -50; i <= 50; i += 20)
for( j = -50; j <= 50; j += 20)
for( k = -50; k <= 50; k += 20) { *(pPoints1++) = i;
*(pPoints1++) = j;
*(pPoints1++) = k;
*(pPoints1++) = 1;
}
return pPoints2;
}
/*Functions used for drawing & Clearing*/
void Plot_NewPoints(float *pPoints) {
int i;
for(i=0;i<num;i++)
putpixel( (int) (*(pPoints+i*2)), (int) (*(pPoints+i*2+1)), 7);
}
void Clear_OldPoints(float *pPoints) {
int i;
for(i=0;i<num;i++)
putpixel( (int) (*(pPoints+i*2)), (int) (*(pPoints+i*2+1)), 0);
}
/*Function used for controlling*/
void Operate(int Switch, float *Ang_Rot_X, float *Ang_Rot_Y, float *Ang_Rot_Z,
float *X_Delta, float *Y_Delta, float *Z_Delta,float *Distance) {
switch(Switch) {
case X_axis_clkwise: (*Ang_Rot_X)--; break;
case X_axis_Cntclkwise: (*Ang_Rot_X)++; break; case Y_axis_clkwise: (*Ang_Rot_Y)--; break;
case Y_axis_Cntclkwise: (*Ang_Rot_Y)++; break; case Z_axis_clkwise: (*Ang_Rot_Z)--; break;
case Z_axis_Cntclkwise: (*Ang_Rot_Z)++; break; case X_Delta_Plus: (*X_Delta)--; break;
case X_Delta_Minus: (*X_Delta)++; break;
case Y_Delta_Plus: (*Y_Delta)--; break;
case Y_Delta_Minus: (*Y_Delta)++; break;
case Z_Delta_Plus: (*Z_Delta)++; break;
case Z_Delta_Minus: (*Z_Delta)--; break;
case Distance_forward: (*Distance)++; break; case Distance_Backward: (*Distance)--; break; default: (*Ang_Rot_Y)++; break;
}
}
int main() {
int i, j, Key;
float *pMatrix1, *pMatrix2;
float *pBasePoints;
float *pPerspectivePoints;
float Ang_Rot_Xaxis, Ang_Rot_Yaxis, Ang_Rot_Zaxis;
float X_Delta, Y_Delta, Z_Delta;
float Distance;
clrscr();
InitGraph();
/*Varieties initialized*/
pBasePoints = Cube();
Ang_Rot_Xaxis = 0;
Ang_Rot_Yaxis = 0;
Ang_Rot_Zaxis = 0;
X_Delta = 0;
Y_Delta = 0;
Z_Delta = 0;
Distance = 200;
Key = 0;
while(Key != ESC) {
if( bioskey(1) )
Key = bioskey(0);
Operate(Key, &Ang_Rot_Xaxis, &Ang_Rot_Yaxis, &Ang_Rot_Zaxis, &X_Delta, &Y_Delta, &Z_Delta, &Distance); SetMatrix_X(Ang_Rot_Xaxis);
SetMatrix_Y(Ang_Rot_Yaxis);
SetMatrix_Z(Ang_Rot_Zaxis);
Set_Transist_Matrix(X_Delta, Y_Delta, Z_Delta);
Set_Perspective_Projection(Distance);
/*The following may be known by you
pay your attention specially to the pair of malloc & free */
pMatrix1 = Matrix_Mul( (float*)X_Rotate_Matrix, 4, 4, (float*)Y_Rotate_Matrix, 4, 4);
pMatrix2 = Matrix_Mul( pMatrix1, 4, 4, (float*)Z_Rotate_Matrix, 4, 4);
free(pMatrix1);
pMatrix1 = Matrix_Mul( pMatrix2, 4, 4, (float*)Transist_Matrix, 4, 4);
free(pMatrix2);
pMatrix2 = Matrix_Mul( pMatrix1, 4, 4, (float*)Perspective_Projection, 4, 4);
free(pMatrix1);
pMatrix1 = Matrix_Mul( pBasePoints, num, 4, pMatrix2, 4, 4);
free(pMatrix2);
Matrix_Convertion( pMatrix1, num);
pPerspectivePoints = Get_X_Y(pMatrix1, num);
Plot_NewPoints(pPerspectivePoints);
delay(5000);
Clear_OldPoints(pPerspectivePoints);
free(pPerspectivePoints); free(pMatrix1); }
free(pBasePoints); closegraph(); return 0; }
5.设三棱锥各顶点坐标为(0,0,20),(20,0,20),(20,0,0),(10,20,10),试编程绘制三面正投影图。
void CProView::OnStart() {
0.70700.40800.70700.4080000.81600
001-⎡⎤⎢⎥--⎢⎥⎢⎥
⎢⎥
⎣⎦
⎥
⎥
⎥⎥⎦
⎤⎢⎢⎢⎢⎣⎡---1000
0943.0000312.00354.00118.00935.0⎥
⎥
⎥⎥⎦
⎤
⎢⎢⎢⎢⎣⎡-1000
01000707.00707.000
1
⎥
⎥
⎥⎥⎦⎤
⎢⎢⎢⎢⎣⎡-1000
01000354.00354.000
1⎥
⎥
⎥⎥⎦
⎤
⎢⎢⎢⎢⎣⎡+=1001000000
01
mq n l
q ⎥
⎥⎥⎥⎦
⎤⎢
⎢⎢⎢⎣⎡
++--=10sin cos 0
10000sin 0
0cos mq lp n m l q p
θ
θθθ⎥
⎥⎥⎥⎦
⎤⎢
⎢⎢⎢⎣⎡++++---1cos )cos sin (sin 0sin cos cos 0
0sin cos 0sin sin sin 0cos 2
1121
12
2
11211nr mp lp n m l m l r
q p
θθθθθθθθθθθθθ(2,0,0)
AB =-(1,0,1)AC =-),,(z y x n =n AB n AC 200n AB x n AC x z ⎧•=-=⎪⎨•=-+=⎪⎩0
0x z =⎧⇒⎨
=⎩
(0,1,0)n = f or y := Ymin to Ymax do
for X := Xmin to Xmax do
if z < [offset]
{
[offset] = z;
[offset] = Ival;
}
face = ;
}
13.试述画家算法的基本思想。
画家方法也称表优先级法。
这种方法的效率介于物体空间算法和图像空间算法之间,它在物体空间预先计算物体各面可见性优先级,然后在图像空间产生消隐图。
它以深度优先级进行排序,按照多边形离观察者的远近来建立一张深度优先级表,离观察者远的优先级低,近的优先级高。
当深度优先级表确定以后,画面中任意两个图形元素在深度上均不重叠,从而解决消隐问题。
14.试述基本的Warnock算法思想。
Warnock算法遵循“细分与占领”的设计思想。
首先在图像空间中设置一个窗口,用递归过程来判定窗口内是否有可见的目标(多边形)。
当判定的窗口中不包含任何多边形或者窗口内只有与一个多边形的相交部分时,称这个多边形为可见。
这时可直接显示该窗口。
否则,就将该窗口分割成若干较小的窗口,直到被分割的子窗口所包含的画面足够简单,可直接显示为止。