资源描述
洛阳理工学院实验报告
系别
计算机与信息工程系
班级
B120531
学号
B12053113
姓名
课程名称
计算机图形学
实验日期
2013-11-7
实验名称
多边形填充算法编程
成绩
实验目的:
熟悉多边形填充算法,掌握MFC图形编程的基本方法和调试技巧。
实验条件:
计算机;VS2008;OpenGL
实验内容:
1.使用MFC技术实现多边形有效边表填充算法,参考界面效果如下:
// ChildView.cpp : CChildView 类的实现
#include "stdafx.h"
#include "demo.h"
#include "ChildView.h"
#include <math.h>
#define Round(d) int(floor(d+0.5))//四舍五入宏定义
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CChildView
CChildView::CChildView()
{
}
CChildView::~CChildView()
{
}
BEGIN_MESSAGE_MAP(CChildView, CWnd)
ON_WM_PAINT()
ON_WM_CREATE()
ON_COMMAND(ID_DRAW_PIC, &CChildView::OnDrawPic)
END_MESSAGE_MAP()
// CChildView 消息处理程序
BOOL CChildView::PreCreateWindow(CREATESTRUCT& cs)
{
if (!CWnd::PreCreateWindow(cs))
return FALSE;
cs.dwExStyle |= WS_EX_CLIENTEDGE;
cs.style &= ~WS_BORDER;
cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS,
::LoadCursor(NULL, IDC_ARROW), reinterpret_cast<HBRUSH>(COLOR_WINDOW+1), NULL);
return TRUE;
}
void CChildView::OnPaint()
{
CPaintDC dc(this); // 用于绘制的设备上下文
// TODO: 在此处添加消息处理程序代码
DrawGraph();
// 不要为绘制消息而调用CWnd::OnPaint()
}
void CChildView::ReadPoint() //点表
{
P[0].x = 50; P[0].y = 100;
P[1].x = -150;P[1].y = 300;
P[2].x = -250;P[2].y = 50;
P[3].x = -150;P[3].y = -250;
P[4].x = 0; P[4].y = -50;
P[5].x = 100; P[5].y = -250;
P[6].x = 300; P[6].y = 150;
}
void CChildView::DrawPolygon(CDC *pDC) //绘制多边形边界
{
CLine *line = new CLine;
CP2 t;
for(int i = 0; i < 7; i++) //绘制多边形
{
if(i == 0)
{
line->MoveTo(pDC, P[i]);
t = P[i];
}
else
{
line->LineTo(pDC, P[i]);
}
}
line->LineTo(pDC, t); //闭合多边形
delete line;
}
void CChildView::DrawGraph() //绘制图形
{
CRect rect; //定义客户区
GetClientRect(&rect); //获得客户区的大小
CDC *pDC = GetDC(); //定义设备上下文指针
pDC->SetMapMode(MM_ANISOTROPIC); //自定义坐标系
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); //矩形与客户区重合
if(!bFill)
DrawPolygon(pDC); //绘制多边形
else
FillPolygon(pDC); //填充多边形
ReleaseDC(pDC); //释放DC
}
void CChildView::FillPolygon(CDC *pDC) //填充多边形
{
for(int i = 0; i < 7; i++) //转储顶点坐标,y坐标取为整数
{
P1[i].x = P[i].x;
P1[i].y = Round(P[i].y);
P1[i].c = CRGB(bRed / 255.0, bGreen / 255.0, bBlue / 255.0);
}
CFill *fill = new CFill; //动态分配内存
fill->SetPoint(P1, 7); //初始化Fill对象
fill->CreateBucket(); //建立桶表
fill->CreateEdge(); //建立边表
fill->Gouraud(pDC); //填充多边形
delete fill; //撤销内存
}
int CChildView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CWnd::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: 在此添加您专用的创建代码
bFill = FALSE;
ReadPoint();
return 0;
}
void CChildView::OnDrawPic()
{
// TODO: 在此添加命令处理程序代码
COLORREF GetClr = RGB(0, 0, 0); //调色板颜色
CColorDialog ccd(GetClr, CC_SOLIDCOLOR);
if(IDOK == ccd.DoModal()) //调用颜色对话框选取填充色
GetClr = ccd.GetColor();
else
return;
bRed = GetRValue(GetClr); //获取红色分量
bGreen = GetGValue(GetClr); //获取绿色分量
bBlue = GetBValue(GetClr); //获取蓝色分量
bFill = TRUE;
Invalidate();
}
2.使用MFC技术实现多边形边缘填充算法,参考界面效果如下:
// demoView.cpp : CdemoView 类的实现
#include "stdafx.h"
#include "demo.h"
#include "demoDoc.h"
#include "demoView.h"
#include <math.h>
#define Round(d) int(floor(d+0.5))//四舍五入宏定义
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CdemoView
IMPLEMENT_DYNCREATE(CdemoView, CView)
BEGIN_MESSAGE_MAP(CdemoView, CView)
// 标准打印命令
ON_COMMAND(ID_FILE_PRINT, &CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_DIRECT, &CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CdemoView::OnFilePrintPreview)
ON_COMMAND(ID_DRAW_PIC, &CdemoView::OnDrawPic)
END_MESSAGE_MAP()
// CdemoView 构造/析构
CdemoView::CdemoView()
{
// TODO: 在此处添加构造代码
}
CdemoView::~CdemoView()
{
}
BOOL CdemoView::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: 在此处通过修改
// CREATESTRUCT cs 来修改窗口类或样式
return CView::PreCreateWindow(cs);
}
// CdemoView 绘制
void CdemoView::OnDraw(CDC* /*pDC*/)
{
CdemoDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
// TODO: 在此处为本机数据添加绘制代码
DrawGraph();
}
// CdemoView 打印
void CdemoView::OnFilePrintPreview()
{
AFXPrintPreview(this);
}
BOOL CdemoView::OnPreparePrinting(CPrintInfo* pInfo)
{
// 默认准备
return DoPreparePrinting(pInfo);
}
void CdemoView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: 添加额外的打印前进行的初始化过程
}
void CdemoView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: 添加打印后进行的清理过程
}
void CdemoView::OnRButtonUp(UINT nFlags, CPoint point)
{
ClientToScreen(&point);
OnContextMenu(this, point);
}
void CdemoView::OnContextMenu(CWnd* pWnd, CPoint point)
{
theApp.GetContextMenuManager()->ShowPopupMenu(IDR_POPUP_EDIT, point.x, point.y, this, TRUE);
}
void CdemoView::ReadPoint() //点表
{
P[0].x = 50; P[0].y = 100;
P[1].x = -150;P[1].y = 300;
P[2].x = -250;P[2].y = 50;
P[3].x = -150;P[3].y = -250;
P[4].x = 0; P[4].y = -50;
P[5].x = 100; P[5].y = -250;
P[6].x = 300; P[6].y = 150;
}
void CdemoView::DrawPolygon(CDC *pDC)
{
for(int i = 0; i < 7; i++) //计算多边形边界
{
if(P[i].x > MaxX)
MaxX = P[i].x;
if(P[i].x < MinX)
MinX = P[i].x;
if(P[i].y > MaxY)
MaxY = P[i].y;
if(P[i].y < MinY)
MinY = P[i].y;
}
CLine *line = new CLine;
CP2 t;
for(int i = 0; i < 7; i++) //绘制多边形
{
if(i == 0)
{
line->MoveTo(pDC, P[i]);
t = P[i];
}
else
{
line->LineTo(pDC, P[i]);
}
}
line->LineTo(pDC, t); //闭合多边形
line->MoveTo(pDC, CP2(MinX, MinY)); //绘制包围盒
line->LineTo(pDC, CP2(MinX, MaxY));
line->LineTo(pDC, CP2(MaxX, MaxY));
line->LineTo(pDC, CP2(MaxX, MinY));
line->LineTo(pDC, CP2(MinX, MinY));
delete line;
}
void CdemoView::FillPolygon(CDC *pDC)
{
COLORREF BClr = RGB(255, 255, 255); //背景色
COLORREF FClr = GetClr; //填充色
int ymin, ymax; //边的最小y值与最大y值
double x, y, k; //x,y当前点,k斜率的倒数
for(int i = 0; i < 7; i++) //循环多边形所有边
{
int j = (i + 1) % 7;
k = (P[i].x - P[j].x) / (P[i].y - P[j].y); //计算/k
if(P[i].y < P[j].y) //得到每条边y的最大值与最小值
{
ymin = Round(P[i].y);
ymax = Round(P[j].y);
x = P[i].x; //得到x|ymin
}
else
{
ymin = Round(P[j].y);
ymax = Round(P[i].y);
x = P[j].x;
}
for(y = ymin; y < ymax; y++) //沿每一条边循环扫描线
{
for(int m = Round(x); m < MaxX; m++) //对每一条扫描线与边的交点的右侧像素循环
{
if(FClr == pDC->GetPixel(m, Round(y))) //如果是填充色
pDC->SetPixelV(m, Round(y), BClr); //置为背景色
else
pDC->SetPixelV(m, Round(y), FClr); //置为填充色
}
x += k; //计算下一条扫描线的x起点坐标
}
}
}
void CdemoView::DrawGraph() //绘制图形
{
CRect rect; //定义客户区
GetClientRect(&rect); //获得客户区的大小
CDC *pDC = GetDC(); //定义设备上下文指针
pDC->SetMapMode(MM_ANISOTROPIC); //自定义坐标系
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); //矩形与客户区重合
if(!bFill)
DrawPolygon(pDC); //绘制多边形
else
FillPolygon(pDC); //填充多边形
ReleaseDC(pDC); //释放DC
}
// CdemoView 诊断
#ifdef _DEBUG
void CdemoView::AssertValid() const
{
CView::AssertValid();
}
void CdemoView::Dump(CDumpContext& dc) const
{
CView::Dump(dc);
}
CdemoDoc* CdemoView::GetDocument() const // 非调试版本是内联的
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CdemoDoc)));
return (CdemoDoc*)m_pDocument;
}
#endif //_DEBUG
// CdemoView 消息处理程序
void CdemoView::OnInitialUpdate()
{
CView::OnInitialUpdate();
// TODO: 在此添加专用代码和/或调用基类
bFill = FALSE;
ReadPoint();
GetClr = RGB(0,0,0);
MinX = MaxX = P[0].x;
MinY = MaxY = P[0].y;
}
void CdemoView::OnDrawPic()
{
// TODO: 在此添加命令处理程序代码
CColorDialog ccd(GetClr, CC_SOLIDCOLOR);
if(IDOK == ccd.DoModal()) //调用颜色对话框选取填充色
GetClr = ccd.GetColor();
else
return;
bFill = TRUE;
Invalidate(FALSE);
}
3.使用MFC技术实现种子填充算法,参考界面效果如下:
// demoView.cpp : CdemoView 类的实现
#include "stdafx.h"
#include "demo.h"
#include "demoDoc.h"
#include "demoView.h"
#include <math.h>
#define Round(d) int(floor(d+0.5))//四舍五入宏定义
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CdemoView
IMPLEMENT_DYNCREATE(CdemoView, CView)
BEGIN_MESSAGE_MAP(CdemoView, CView)
// 标准打印命令
ON_COMMAND(ID_FILE_PRINT, &CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_DIRECT, &CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CdemoView::OnFilePrintPreview)
ON_WM_LBUTTONDOWN()
ON_COMMAND(ID_DRAW_PIC, &CdemoView::OnDrawPic)
END_MESSAGE_MAP()
// CdemoView 构造/析构
CdemoView::CdemoView()
{
// TODO: 在此处添加构造代码
bFill = FALSE;
SeedClr = RGB(255, 0, 0);
}
CdemoView::~CdemoView()
{
}
BOOL CdemoView::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: 在此处通过修改
// CREATESTRUCT cs 来修改窗口类或样式
return CView::PreCreateWindow(cs);
}
// CdemoView 绘制
void CdemoView::OnDraw(CDC* /*pDC*/)
{
CdemoDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
// TODO: 在此处为本机数据添加绘制代码
DrawGraph();
}
// CdemoView 打印
void CdemoView::OnFilePrintPreview()
{
AFXPrintPreview(this);
}
BOOL CdemoView::OnPreparePrinting(CPrintInfo* pInfo)
{
// 默认准备
return DoPreparePrinting(pInfo);
}
void CdemoView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: 添加额外的打印前进行的初始化过程
}
void CdemoView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: 添加打印后进行的清理过程
}
void CdemoView::OnRButtonUp(UINT nFlags, CPoint point)
{
ClientToScreen(&point);
OnContextMenu(this, point);
}
void CdemoView::OnContextMenu(CWnd* pWnd, CPoint point)
{
theApp.GetContextMenuManager()->ShowPopupMenu(IDR_POPUP_EDIT, point.x, point.y, this, TRUE);
}
// CdemoView 诊断
#ifdef _DEBUG
void CdemoView::AssertValid() const
{
CView::AssertValid();
}
void CdemoView::Dump(CDumpContext& dc) const
{
CView::Dump(dc);
}
CdemoDoc* CdemoView::GetDocument() const // 非调试版本是内联的
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CdemoDoc)));
return (CdemoDoc*)m_pDocument;
}
#endif //_DEBUG
void CdemoView::DrawGraph()//绘制图形
{
CDC *pDC = GetDC(); //定义设备上下文指针
GetClientRect(&rect); //获得客户区的大小
pDC->SetMapMode(MM_ANISOTROPIC); //自定义坐标系
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); //矩形与客户区重合
CDC MemDC;//内存DC
CBitmap NewBitmap, *pOldBitmap; //内存中承载图像的位图
MemDC.CreateCompatibleDC(pDC); //建立与屏幕pDC兼容的MemDC
NewBitmap.LoadBitmap(IDB_BITMAP1); //导入空心汉字位图
pOldBitmap = MemDC.SelectObject(&NewBitmap);//将兼容位图选入MemDC
MemDC.SetMapMode(MM_ANISOTROPIC); //MemDC自定义坐标系
MemDC.SetWindowExt(rect.Width(), rect.Height());
MemDC.SetViewportExt(rect.Width(), -rect.Height());
MemDC.SetViewportOrg(rect.Width() / 2, rect.Height() / 2);
pDC->BitBlt(-rect.Width() / 2, -rect.Height() / 2, rect.Width(), rect.Height(), &MemDC, -rect.Width() / 2, -rect.Height() / 2, SRCCOPY);//将内存位图拷贝到屏幕
if(bFill)
CharFill(pDC); //填充空心汉字
MemDC.SelectObject(pOldBitmap); //恢复位图
NewBitmap.DeleteObject(); //删除位图
MemDC.DeleteDC(); //删除MemDC
ReleaseDC(pDC); //释放DC
}
void CdemoView::CharFill(CDC *pDC) //文字填充函数
{
COLORREF BoundaryClr = RGB(0,0,0); //边界色
BOOL bSpanFill;
pHead = new CStackNode; //建立栈结点
pHead->pNext = NULL; //栈头结点的指针域总为空
Push(Seed); //种子像素入栈
int x, y, x0 = Round(Seed.x), y0 = Round(Seed.y);//x,y用于判断种子与图形的位置关系
x = x0 - 1;
while(pDC->GetPixel(x, y0) != BoundaryClr && pDC->GetPixel(x, y0) != SeedClr )//左方判断
{
x--;
if(x <= -rect.Width() / 2)
{
MessageBox(L"种子不在图形之内", L"警告");//到达客户区最左端
return;
}
}
y = y0 + 1;
while(pDC->GetPixel(x0, y) != BoundaryClr && pDC->GetPixel(x0, y) != SeedClr)//上方判断
{
y++;
if(y >= rect.Height() / 2)//到达客户区最上端
{
MessageBox(L"种子不在图形之内", L"警告");
return;
}
}
x = x0 + 1;
while(pDC->GetPixel(x, y0) != BoundaryClr && pDC->GetPixel(x, y0) != SeedClr)//右方判断
{
x++;
if(x >= rect.Width() / 2)//到达客户区最右端
{
MessageBox(L"种子不在图形之内", L"警告");
return;
}
}
y = y0 - 1;
while(pDC->GetPixel(x0, y) != BoundaryClr && pDC->GetPixel(x0, y) != SeedClr)//下方判断
{
y--;
if(y <= -rect.Height() / 2)//到达客户区最下端
{
MessageBox(L"种子不在图形之内", L"警告");
return;
}
}
double xleft, xright;//区间最左端与最右端像素
CP2 PopPoint, PointTemp;
while(pHead->pNext != NULL)//如果栈不为空
{
Pop(PopPoint);
if(pDC->GetPixel(Round(PopPoint.x), Round(PopPoint.y)) == SeedClr)
continue;
// 分别向左和向右填充扫描线
PointTemp = PopPoint;
while(pDC->GetPixel(Round(PointTemp.x), Round(PointTemp.y)) != BoundaryClr && pDC->GetPixel(Round(PointTemp.x), Round(PointTemp.y)) != SeedClr)
{
pDC->SetPixelV(Round(PointTemp.x), Round(PointTemp.y), SeedClr);
PointTemp.x++;
}
xright = PointTemp.x - 1;
PointTemp.x = PopPoint.x - 1;
while(pDC->GetPixel(Round(PointTemp.x), Round(PointTemp.y)) != BoundaryClr && pDC->GetPixel(Round(PointTemp.x), Round(PointTemp.y)) != SeedClr)
{
pDC->SetPixelV(Round(PointTemp.x), Round(PointTemp.y), SeedClr);
PointTemp.x--;
}
xleft=PointTemp.x + 1;
//处理上一条扫描线
PointTemp.x = xleft;
PointTemp.y = PointTemp.y + 1;
while(PointTemp.x < xright)
{
bSpanFill = FALSE;
while(pDC->GetPixel(Round(PointTemp.x), Round(PointTemp.y)) != BoundaryClr && pDC->GetPixel(Round(PointTemp.x), Round(PointTemp.y)) != SeedClr)
{
bSpanFill = TRUE;
PointTemp.x++;
}
if(bSpanFill)
{
if(PointTemp.x == xright && pDC->GetPixel(Round(PointTemp.x), Round(PointTemp.y)) != BoundaryClr && pDC->GetPixel(Round(PointTemp.x), Round(PointTemp.y)) != SeedClr)
PopPoint = PointTemp;
else
PopPoint.x = PointTemp.x - 1; PopPoint.y = PointTemp.y;
Push(PopPoint);
bSpanFill = FALSE;
}
while((pDC->GetPixel(Round(PointTemp.x), Round(PointTemp.y)) == BoundaryClr && PointTemp.x < xright) || (pDC->GetPixel(Round(PointTemp.x), Round(PointTemp.y)) == SeedClr && PointTemp.x < xright))
PointTemp.x++;
}
//处理下一条扫描线
PointTemp.x = xleft;
PointTemp.y = PointTemp.y - 2;
while(PointTemp.x < xright)
{
bSpanFill = FALSE;
while(pDC->GetPixel(Round(PointTemp.x), Round(PointTemp.y)) != BoundaryClr && pDC->GetPixel(Ro
展开阅读全文