扫描线画法.docx
《扫描线画法.docx》由会员分享,可在线阅读,更多相关《扫描线画法.docx(17页珍藏版)》请在冰豆网上搜索。
![扫描线画法.docx](https://file1.bdocx.com/fileroot1/2023-1/22/cb09c6eb-a4d7-4f6f-9041-7c82ab68be7e/cb09c6eb-a4d7-4f6f-9041-7c82ab68be7e1.gif)
扫描线画法
//forstu.cpp:
定义应用程序的入口点。
//
#include"stdafx.h"
#include"stdio.h"
#include"forstu.h"
#defineMAX_LOADSTRING100
#defineWINDOW_HEIGHT600
#defineMAX_POINT256
#defineCOLOR255
typedefenumtdrawtype{
LINE_DDA=1,
LINE_BR,
CIRCLE_BR,
AET
}drawtype;
typedefstructtEdge{
intyMax;
floatxStart,dx;
structtEdge*next;
}Edge;
typedefstructtdcPt{
intx;
inty;
}dcPt;
//全局变量:
HINSTANCEhInst;//当前实例
TCHARszTitle[MAX_LOADSTRING];//标题栏文本
TCHARszWindowClass[MAX_LOADSTRING];//主窗口类名
//当前绘制类型
drawtypecurtype;
//用于AET的变量
FILE*fp;
dcPtvertexs[256];
inti,cnt,x;
//二维图形栅格化生成算法
voidddaline(HDChdc,intx1,inty1,intx2,inty2);
intsign(floatx);
voidbresenhamline(HDChdc,intx1,inty1,intx2,inty2);
voidbresenhamcircle(HDChdc,intxc,intyc,intr);
voidcyclepoint(HDChdc,intx,inty,intxc,intyc);
//下面的函数用于AET算法
voidinsertEdge(Edge*list,Edge*edge);
intyNext(intk,intcnt,dcPt*pts);
voidmakeEdgeRec(dcPtlower,dcPtupper,intyComp,Edge*edge,Edge*edges[]);
voidbuildEdgeList(intcnt,dcPt*pts,Edge*edges[]);
voidbuildActiveList(intscan,Edge*active,Edge*edges[]);
voidfillScan(HDChdc,intscan,Edge*active);
voiddeleteAfter(Edge*q);
voidupdateActiveList(intscan,Edge*active);
voidresortActiveList(Edge*active);
voidscanFill(HDChdc,intcnt,dcPt*pts);
//此代码模块中包含的函数的前向声明:
ATOMMyRegisterClass(HINSTANCEhInstance);
BOOLInitInstance(HINSTANCE,int);
LRESULTCALLBACKWndProc(HWND,UINT,WPARAM,LPARAM);
LRESULTCALLBACKAbout(HWND,UINT,WPARAM,LPARAM);
intAPIENTRY_tWinMain(HINSTANCEhInstance,
HINSTANCEhPrevInstance,
LPTSTRlpCmdLine,
intnCmdShow)
{
//TODO:
在此放置代码。
MSGmsg;
HACCELhAccelTable;
//初始化全局字符串
LoadString(hInstance,IDS_APP_TITLE,szTitle,MAX_LOADSTRING);
LoadString(hInstance,IDC_FORSTU,szWindowClass,MAX_LOADSTRING);
MyRegisterClass(hInstance);
//执行应用程序初始化:
if(!
InitInstance(hInstance,nCmdShow))
{
returnFALSE;
}
hAccelTable=LoadAccelerators(hInstance,(LPCTSTR)IDC_FORSTU);
//主消息循环:
while(GetMessage(&msg,NULL,0,0))
{
if(!
TranslateAccelerator(msg.hwnd,hAccelTable,&msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return(int)msg.wParam;
}
//
//函数:
MyRegisterClass()
//
//目的:
注册窗口类。
//
//注释:
//
//仅当希望在已添加到Windows95的
//“RegisterClassEx”函数之前此代码与Win32系统兼容时,
//才需要此函数及其用法。
调用此函数
//十分重要,这样应用程序就可以获得关联的
//“格式正确的”小图标。
//
ATOMMyRegisterClass(HINSTANCEhInstance)
{
WNDCLASSEXwcex;
wcex.cbSize=sizeof(WNDCLASSEX);
wcex.style=CS_HREDRAW|CS_VREDRAW;
wcex.lpfnWndProc=(WNDPROC)WndProc;
wcex.cbClsExtra=0;
wcex.cbWndExtra=0;
wcex.hInstance=hInstance;
wcex.hIcon=LoadIcon(hInstance,(LPCTSTR)IDI_FORSTU);
wcex.hCursor=LoadCursor(NULL,IDC_ARROW);
wcex.hbrBackground=(HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName=(LPCTSTR)IDC_FORSTU;
wcex.lpszClassName=szWindowClass;
wcex.hIconSm=LoadIcon(wcex.hInstance,(LPCTSTR)IDI_SMALL);
returnRegisterClassEx(&wcex);
}
//
//函数:
InitInstance(HANDLE,int)
//
//目的:
保存实例句柄并创建主窗口
//
//注释:
//
//在此函数中,我们在全局变量中保存实例句柄并
//创建和显示主程序窗口。
//
BOOLInitInstance(HINSTANCEhInstance,intnCmdShow)
{
HWNDhWnd;
hInst=hInstance;//将实例句柄存储在全局变量中
hWnd=CreateWindow(szWindowClass,szTitle,WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,0,CW_USEDEFAULT,0,NULL,NULL,hInstance,NULL);
if(!
hWnd)
{
returnFALSE;
}
ShowWindow(hWnd,nCmdShow);
UpdateWindow(hWnd);
returnTRUE;
}
//
//函数:
WndProc(HWND,unsigned,WORD,LONG)
//
//目的:
处理主窗口的消息。
//
//WM_COMMAND-处理应用程序菜单
//WM_PAINT-绘制主窗口
//WM_DESTROY-发送退出消息并返回
//
//
LRESULTCALLBACKWndProc(HWNDhWnd,UINTmessage,WPARAMwParam,LPARAMlParam)
{
intwmId,wmEvent;
PAINTSTRUCTps;
HDChdc;
//用于AET的变量
FILE*fp;
dcPtvertexs[256];
inti,cnt;
switch(message)
{
caseWM_COMMAND:
wmId=LOWORD(wParam);
wmEvent=HIWORD(wParam);
//分析菜单选择:
switch(wmId)
{
caseIDM_ABOUT:
DialogBox(hInst,(LPCTSTR)IDD_ABOUTBOX,hWnd,(DLGPROC)About);
break;
caseIDM_EXIT:
DestroyWindow(hWnd);
break;
caseID_BR:
curtype=LINE_BR;
InvalidateRect(hWnd,NULL,TRUE);
UpdateWindow(hWnd);
break;
caseID_DDA:
curtype=LINE_DDA;
InvalidateRect(hWnd,NULL,TRUE);
UpdateWindow(hWnd);
break;
caseID_CIRCLE_BR:
curtype=CIRCLE_BR;
InvalidateRect(hWnd,NULL,TRUE);
UpdateWindow(hWnd);
break;
caseID_AET:
curtype=AET;
InvalidateRect(hWnd,NULL,TRUE);
UpdateWindow(hWnd);
break;
default:
returnDefWindowProc(hWnd,message,wParam,lParam);
}
break;
caseWM_PAINT:
hdc=BeginPaint(hWnd,&ps);
//TODO:
在此添加任意绘图代码...
switch(curtype)
{
caseLINE_DDA:
ddaline(hdc,50,70,100,150);//红色直线
break;
caseLINE_BR:
bresenhamline(hdc,50,70,200,150);//兰色直线
break;
caseCIRCLE_BR:
bresenhamcircle(hdc,350,250,100);
break;
caseAET:
fp=fopen("polygon1.ply","rt");
fscanf(fp,"%d%d",&(vertexs[0].x),&(vertexs[0].y));
i=0;
do{
i++;
fscanf(fp,"%d%d",&(vertexs[i].x),&(vertexs[i].y));
}while((vertexs[0].x!
=vertexs[i].x||vertexs[0].y!
=vertexs[i].y)&&!
feof(fp));
fclose(fp);
cnt=i;
scanFill(hdc,cnt,vertexs);
break;
default:
break;
}
EndPaint(hWnd,&ps);
break;
caseWM_DESTROY:
PostQuitMessage(0);
break;
default:
returnDefWindowProc(hWnd,message,wParam,lParam);
}
return0;
}
//“关于”框的消息处理程序。
LRESULTCALLBACKAbout(HWNDhDlg,UINTmessage,WPARAMwParam,LPARAMlParam)
{
switch(message)
{
caseWM_INITDIALOG:
returnTRUE;
caseWM_COMMAND:
if(LOWORD(wParam)==IDOK||LOWORD(wParam)==IDCANCEL)
{
EndDialog(hDlg,LOWORD(wParam));
returnTRUE;
}
break;
}
returnFALSE;
}
//-----------------------直线的DDA算法------------------------------------------------------
voidddaline(HDChdc,intx1,inty1,intx2,inty2)
{
intlength,i;
floatdx,dy,x,y;
length=max(abs(x2-x1),abs(y2-y1));
dx=(float)(x2-x1)/length;
dy=(float)(y2-y1)/length;
if(dx==0){for(i=y1;i<=y2;i++)SetPixel(hdc,x1,i,RGB(COLOR,0,0));}
elseif(dy==0){for(i=x1;i<=x2;i++)SetPixel(hdc,i,y1,RGB(COLOR,0,0));}
else
{
x=(float)(x1+0.5*sign(dx));
y=(float)(y1+0.5*sign(dy));
for(i=1;i<=length;i++)
{
SetPixel(hdc,int(x),int(y),RGB(COLOR,0,0));
x=x+dx;
y=y+dy;
}
}
}
intsign(floatx)
{
if(x>0)return1;
elseif(x<0)return-1;
elsereturn0;
}
//--------------------------直线的Bresenham算法---------------------------------------------------
voidbresenhamline(HDChdc,intx1,inty1,intx2,inty2)
{
intx,y,dx,dy,i;
floatm,e;
x=x1;y=y1;
dx=x2-x1;dy=y2-y1;
if(dx==0){for(i=y1;i<=y2;i++)SetPixel(hdc,x1,i,RGB(COLOR,0,0));}
elseif(dy==0){for(i=x1;i<=x2;i++)SetPixel(hdc,i,y1,RGB(COLOR,0,0));}
else
{m=(float)dy/(float)dx;
e=float(m-0.5);
for(i=1;i<=dx;i++)
{
SetPixel(hdc,x,y,RGB(0,0,COLOR));
if(e>=0){y=y+1;e=e-1;}
x=x+1;e=e+m;
}
}
}
//------------------------------Bresenham的中点画圆法-----------------------------------------------
voidbresenhamcircle(HDChdc,intxc,intyc,intr)
{
intx,y,d;
x=0;y=r;
d=3-2*r;
while(x{
cyclepoint(hdc,x,y,xc,yc);
if(d>=0){d=d+4*(x-y)+10;y--;}
elsed=d+4*x+6;
x++;
}
if(x==y)cyclepoint(hdc,x,y,xc,yc);
}
voidcyclepoint(HDChdc,intx,inty,intxc,intyc)
{
SetPixel(hdc,x+xc,y+yc,RGB(COLOR,0,0));
SetPixel(hdc,y+xc,x+yc,RGB(COLOR,COLOR,0));
SetPixel(hdc,x+xc,-y+yc,RGB(COLOR,0,COLOR));
SetPixel(hdc,y+xc,-x+yc,RGB(0,COLOR,COLOR));
SetPixel(hdc,-x+xc,-y+yc,RGB(0,COLOR,0));
SetPixel(hdc,-y+xc,-x+yc,RGB(0,0,COLOR));
SetPixel(hdc,-y+xc,x+yc,RGB(COLOR,0,0));
SetPixel(hdc,-x+xc,y+yc,RGB(0,0,COLOR));
}
/*按照y值升序进行插入排序*/
voidinsertEdge(Edge*list,Edge*edge)
{
Edge*p,*q=list;
p=q->next;
while(p!
=NULL){
if(edge->xStartxStart)
p=NULL;
else{
q=p;
p=p->next;
}
}
edge->next=q->next;
q->next=edge;
}
/*返回给定边下一条非水平边的y值*/
intyNext(intk,intcnt,dcPt*pts)
{
intj;
if((k+1)>(cnt-1))
j=0;
else
j=k+1;
while(pts[k].y==pts[j].y)
if((j+1)>(cnt-1))
j=0;
else
j++;
return(pts[j].y);
}
/*生成各个边对应的结点信息并插入到边表中*/
voidmakeEdgeRec(dcPtlower,dcPtupper,intyComp,
Edge*edge,Edge*edges[])
{
edge->dx=(float)(upper.x-lower.x)
/(upper.y-lower.y);
edge->xStart=lower.x;
/*对特殊交点个数的处理,其中包括了0、1、2个交点对应的特殊情况。
*/
if(upper.yedge->yMax=upper.y-1;
else
edge->yMax=upper.y;
/*将该边对应的结点加入边表中*/
insertEdge(edges[lower.y],edge);
}
/*建立初始边表*/
voidbuildEdgeList(intcnt,dcPt*pts,Edge*edges[])
{
Edge*edge;
dcPtv1,v2;
inti,yPrev=pts[cnt-2].y;
v1.x=pts[cnt-1].x;
v1.y=pts[cnt-1].y;
for(i=0;iv2=pts[i];
if(v1.y!
=v2.y){/*非水平边*/
edge=(Edge*)malloc(sizeof(Edge));
if(v1.ymakeEdgeRec(v1,v2,yNext(i,cnt,pts),
edge,edges);
else/*该边y方向按照多边形边前进方向从大到小*/
makeEdgeRec(v2,v1,yPrev,edge,edges);
}
yPrev=v1.y;
v1=v2;
}
}
/*从边表中取出给定扫描线对应的链表,插入活性边表中*/
voidbuildActiveList(intscan,Edge*active,
Edge*edges[])
{
Edge*p,*q;
p=edges[scan]->next;
while(p){
q=p->next;
insertEdge(active,p);
p=q;
}
}
/*单条扫描线对应的填充操作*/
voidfillScan(HDChdc,intscan,Edge*active)
{
Edge*p1,*p2;
inti;
p1=active->next;
while(p1){
p2=p1->next;
for(i=p1->xStart;ixStart;i++)
SetPixel(hdc,(int)i,scan,RGB(255,0,0));
p1=p2->next;
}
}
/*删除单项链表中节点q指向的下一个边节点*/
voiddeleteAfter(Edge*q)
{
Edge*p=q->next;
q->next=p->next;
free(p);
}
/*更新活性边表:
将达到yMax的边对应的结点从活性边表中删除,然后将各个边对应的x起点加上增量1/k*/
v