计算机图形学
实验报告
学号:
姓名:
一、Bresenham算法
1、算法思想:1画起点(x1, y1); 2.准备画下一个点,X坐标加1,判断如果达到终点,则完成。否则找下一个点,由图可知要画的点要么为当前点的右邻接点,要么是当前点的右上邻接点。2.1.如果线段ax+by+c=0与x=x1+1的交点y坐标大于(y+*y+1))/2则选右上那个点2.2.否则选右下那个点;3.画点;4.跳回第2步; 5.结束。
2、优点:Bresenham算法也是采用递推步进的办法,但与简单DDA算法不同,它是根据一个简单的判别式来判断在另一个方向上是否也需要步进一个单位,这样就避免了许多实数运算。
3、运行结果:
二、中点Bresenham算法画圆
1、算法思想:1、赋初值:x=0,y=R,d=3-2R;2、画点(x,y)(同时画8个点);3、若d<0,则d=d+4x+6,否则d=d+4(x-y)+10,y=y-1;4、赋值:x=x+1;5、若x<y,转步骤2,否则画点(x,y)结束。
2、优点:将一个象限内的相邻八分圆弧对于分割两个部分的四十五度是对称的,利用园对称性的这种方法仅需计算从x=0到x=y段内的点就可得到整个园的所有像素位置,但计算时间仍很大,用Bresenham画线算法以决策参数的增加量计算为基础,仅包括简单的整数操作。
3、运行结果:
三、编程实现绘制一段三次Bezier曲线
1、理解:Bezier曲线通过控制曲线上的四个点(起始点、终止点以及两个相互分离的中间点)来创造、编辑图形。其中起重要作用的是位于曲线中央的控制线。这条线是虚拟的,中间与贝塞尔曲线交叉,两端是控制端点。移动两端的端点时贝塞尔曲线改变曲线的曲率(弯曲的程度);移动中间点(也就是移动虚拟的控制线)时,贝塞尔曲线在起始点和终止点锁定的情况下做均匀移动。
四、线段的编码裁剪算法
1、基本步骤:1.按照编码规则,确定被裁剪线段P1 P2 的端点编码;2、对两个端点的编码进行逻辑与运算:若结果为非零,则线段全部在裁剪窗口之外,舍弃,否则,若全为零,则线段全在窗口内,可直接接受;3、否则,求线段与窗口边的交点,舍弃在裁剪窗口外同侧的部分线段,对留下的线段重新执行2步骤。
2、优点:通过初试测试来减少要计算的交点数目从而加快线段裁剪算法的速度。
五、总结
通过本次实验,进一步加深了对于基本画图算法的理解,特别是对于Bresenham算法和画圆算法,巩固了编程能力。
五、源程序
1、Bresenham算法
include "graphics.h"
#include<stdio.h>
#include<math.h>
#include<conio.h>
void midbresenhamline(int x0,int y0,int x1,int y1,int color)
{ int dx,dy,d,upincre,downincre,x,y;
if(x0>x1)
{ x=x1;x1=x0;x0=x;
y=y1;y1=y0;y0=y; }
x=x0;y=y0;
dx=x1-y0;dy=y1-y0;
d=dx-2*dy;
upincre=2*dx-2*dy;downincre=-2*dy;
while(x<=x1)
{ putpixel(x,y,color);
x++;
if(d<0){
y++;
d+=upincre; }
else
d+=downincre;
}
}
void main()
{ int gdriver ,gmode
gdriver = DETECT;
initgraph(&gdriver,&gmode,"C:\\TC20\\BGI");
midbresenhamline(1,1,200,400,14);
setbkcolor(BLACK);
getchar();
closegraph();
}
2、中点Bresenham算法画圆
#include <math.h>
#include <graphics.h> /*预定义库函数*/
void circlePoint(int x,int y) /*八分法画圆程序*/
{
circle(320+x*20,240+y*20,3);
circle(320+y*20,240+x*20,3);
circle(320-y*20,240+x*20,3);
circle(320-x*20,240+y*20,3);
circle(320-x*20,240+y*20,3);
circle(320-x*20,240-y*20,3);
circle(320-y*20,240-x*20,3);
circle(320+y*20,240-x*20,3);
circle(320+x*20,240-y*20,3);
}
void MidBresenhamcircle(int r) /* 中点Bresenham算法画圆的程序 */
{
int x,y,d;
x=0;y=r;d=1-r; /* 计算初始值 */
while(x<y)
{ circlePoint(x,y); /* 绘制点(x,y)及其在八分圆中的另外7个对称点 */
if(d<0) d+=2*x+3; /* 根据误差项d的判定,决定非最大位移方向上是走还是不走 */
else
{ d+=2*(x-y)+5;
y--;
}
x++;
delay(900000);
} /* while */
}
main()
{
int i,j,r,graphmode,graphdriver;
detectgraph(&graphdriver,&graphmode);
initgraph(&graphdriver,&graphmode," ");
printf("中点Bresenhamcircle算法画圆的程序\n"); /*提示信息*/
printf("注重 |r|<=11");
printf("\n输入半径值 r:");
scanf("%d",&r);
printf("按任意键显示图形...");
getch();
cleardevice();
setbkcolor(BLACK);
for(i=20;i<=620;i+=20) /*使用双循环画点函数画出表格中的纵坐标*/
for(j=20;j<=460;j++)
putpixel(i,j,2);
for(j=20;j<=460;j+=20) /*使用双循环画点函数画出表格中的横坐标*/
for(i=20;i<=620;i++)
putpixel(i,j,2);
outtextxy(320,245,"0"); /*原点坐标*/
outtextxy(320-5*20,245,"-5");circle(320-5*20,240,2); /*横坐标值*/
outtextxy(320+5*20,245,"5");circle(320+5*20,240,2);
outtextxy(320-10*20,245,"-10");circle(320-10*20,240,2);
outtextxy(320+10*20,245,"10");circle(320+10*20,240,2);
outtextxy(320-15*20,245,"-15");circle(320-15*20,240,2);
outtextxy(320+15*20,245,"15");circle(320+15*20,240,2);
outtextxy(320,240-5*20,"-5");circle(320,240-5*20,2); /*纵坐标值*/
outtextxy(320,240+5*20,"5");circle(320,240+5*20,2);
outtextxy(320,240-10*20,"-10");circle(320,240-10*20,2);
outtextxy(320,240+10*20,"10");circle(320,240+10*20,2);
outtextxy(20,10,"The center of the circle is (0,0) "); /*坐标轴左上角显示提示信息*/
setcolor(RED); /*标记坐标轴*/
line(20,240,620,240); outtextxy(320+15*20,230,"X");
line(320,20,320,460); outtextxy(330,20,"Y");
setcolor(YELLOW);
MidBresenhamcircle(r);
setcolor(BLUE); /*绘制圆*/
circle(320,240,r*20);
setcolor(2);
getch();
closegraph();
}
3、Bezier曲线
#i
nclude<windows.h>
#include<stdlib.h>
#include<time.h>
#define NUM 10
LRESULT CALLBACK Winproc(HWND,UINT,WPARAM,LPARAM);
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstanc,LPSTR lpCmdLine,int nShowCmd)
{
MSG msg;
static TCHAR szClassName[] = TEXT;
HWND hwnd;
WNDCLASS wc;
wc.cbClsExtra =0;
wc.cbWndExtra =0;
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.hCursor = LoadCursor(NULL,IDC_ARROW);
wc.hIcon = LoadIcon(NULL,IDI_APPLICATION);
wc.hInstance = hInstance;
wc.lpfnWndProc = Winproc;
wc.lpszClassName = szClassName;
wc.lpszMenuName = NULL;
wc.style = CS_HREDRAW|CS_VREDRAW;
if(!RegisterClass(&wc))
{
MessageBox(NULL);
return 0;
}
hwnd = CreateWindow(szClassName,szClassName,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,CW_USEDEFAULT,
CW_USEDEFAULT,CW_USEDEFAULT,
NULL,NULL,hInstance,NULL);
ShowWindow(hwnd,SW_SHOWMAXIMIZED);
UpdateWindow(hwnd);
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK Winproc(HWND hwnd,UINT message, WPARAM wparam,LPARAM lparam)
{
PAINTSTRUCT ps;
HDC hdc;
static POINT pt[NUM];
TEXTMETRIC tm;
static int cxClient,cyClient;
HPEN hpen;
int i,j,k,n,t;
switch(message)
{
case WM_CREATE:
static int cxchar;
hdc = GetDC(hwnd);
GetTextMetrics(hdc,&tm);
cxchar = tm.tmAveCharWidth;
ReleaseDC(hwnd,hdc);
case WM_SIZE:
cxClient = LOWORD(lparam);
cyClient = HIWORD(lparam);
return 0;
case WM_PAINT:
hdc = GetDC(hwnd);
srand(time(0));
Rectangle(hdc,0,0,cxClient,cyClient);
for(i=0; i<500; i++)
{
SelectObject(hdc,GetStockObject(WHITE_PEN));
PolyBezier(hdc,pt,NUM);
for(j=0; j<NUM; j++)
{
pt[j].x = rand()%cxClient;
pt[j].y = rand()%cyClient;
}
hpen = CreatePen(PS_INSIDEFRAME,3,RGB(rand()%256,rand()%256,rand()%256));
DeleteObject(SelectObject(hdc,hpen));
PolyBezier(hdc,pt,NUM);
for(k=0; k<50000000;k++);
}
for(i=0; i<100;i++)
{
Ellipse(hdc,rand()%cxClient,rand()%cyClient,rand()%cxClient,rand()%cyClient);
}
if((n=(n+j)/2)>cxchar*20) n=cxchar*20;
SetTextColor(hdc,RGB(rand()%256,rand()%256,rand()%256));
TextOut(hdc,n/2,(t+k)/2,);
ReleaseDC(hwnd,hdc);
DeleteObject(hpen);
ValidateRect(hwnd,NULL);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd,message,wparam,lparam);
}
4、编码裁剪算法
#include<stdio.h>
#include<graphics.h>
#define LEFT 1
#define RIGHT 2
#define BOTTOM 4
#define TOP 8
#define FALSE 0
#define TRUE 1
void Line_Clipping(x1,y1,x2,y2,xw_xmin,yw_ymin,xw_xmax,yw_ymax)
float x1,y1,x2,y2,xw_xmin,yw_ymin,xw_xmax,yw_ymax;
{
int draw,done;
int code1,code2,code;
float x,y;
draw=FALSE;done=FALSE;
code1=get_code(x1,y1,xw_xmin,yw_ymin,xw_xmax,yw_ymax);
code2=get_code(x2,y2,xw_xmin,yw_ymin,xw_xmax,yw_ymax);
while(!done)
{
if(code1==0&&code2==0)
{
draw=TRUE;done=TRUE;
}
else if(code1&code2!=0)
{
done =TRUE;
}else
{
if(code1!=0)
code=code1;
else
code=code2;
if((code&TOP)!=0)
{y=yw_ymax;
x=x1+(y-y1)*(x2-x1)/(y2-y1);
}
else if((code&BOTTOM)!=0)
{
y=yw_ymin;
x=x1+(y-y1)*(x2-x1)/(y2-y1);
}
else if((code&RIGHT)!=0)
{
x=xw_xmax;
y=y1+(x-x1)*(y2-y1)/(x2-x1);
}
else if((code&LEFT)!=0)
{
x=xw_xmin;
y=y1+(x-x1)*(y2-y1)/(x2-x1);
}
if(code==code1)
{
x1=x;
y1=y;
code1=get_code(x1,y1,xw_xmin,yw_ymin,xw_xmax,yw_ymax);
}
else
{
x2=x;
y2=y;
code2=get_code(x2,y2,xw_xmin,yw_ymin,xw_xmax,yw_ymax);
}
}
if(draw)
{
setcolor(8);
line(x1,y1,x2,y2);
}
}
}
int get_code(x,y,xw_xmin,yw_ymin,xw_xmax,yw_ymax)
float x,y,xw_xmin,yw_ymin,xw_xmax,yw_ymax;
{
int code;
code=0;
if(y>yw_ymax)
code|=TOP;
else if(y<yw_ymin)
code|=BOTTOM;
if(x>xw_xmax)
code|=RIGHT;
else if(x<xw_xmin)
code|=LEFT;
return code;
}
void main()
{
float x1=76,y1=40,x2=60,y2=80,xw_xmin=50,xw_xmax=80,yw_ymin=50,yw_ymax=70;
int gdriver=DETECT,gmode;
initgraph(&gdriver,&gmode,"C:\\TURBOC2");
setcolor(5);
line(x1,y1,x2,y2);
rectangle(xw_xmin,yw_ymin,xw_xmax,yw_ymax);
getch();
cleardevice();
setcolor(8);
rectangle(xw_xmin,yw_ymin,xw_xmax,yw_ymax);
Line_Clipping(x1,y1,x2,y2,xw_xmin,yw_ymin,xw_xmax,yw_ymax);
getch();
closegraph();
}