多边形的填充实验经典
贵州大学--实验三-多边形填充算法
贵州大学实验报告学院:计算机科学与信息专业:软件工程班级:102班边界上的象素填充所遵循的规则为:“左闭右开”,“下闭上开”(将左边界和下边界的点算为内部,而将右边界和上边界算为外部)顶点:“上开下闭”。
几种特殊情况:1.扫描线交于一顶点,共享的两条边分另处于扫描线的两边,这时交点只取一个。
2.共享交点的两条边处于扫描线的上方,这时交点取二个。
3.共享交点的两条边处于扫描线的下方,这时交点取0个。
4.水平边在算法中不起任何作用,可不考虑。
活性边表(提高效率):为了减少求交的计算量,要利用一条边与相继的两条扫描线的交点的连贯性。
在处理一条扫描线时只对活性边(与它相交的多边形的边)进行求交运算。
把交点按x增加方向存在一个链表(活性边表)中。
活性边:与当前扫描线相交的边。
活性边表(AEL):按交点x的增量顺序存放在一个链表中,该链表称作活性边表(AEL)。
二、种子填充算法种子填充首先假定区域由封闭轮廓线围成,且轮廓线内某点是已知的,然后开始搜索与种子点相邻且位于轮廓线内的点。
如果这相邻点不在轮廓线内,则已达到轮廓线的边界;如果相邻点在轮廓线之内,则这相邻点成为新的种子点,继续搜索下去。
只适用于光栅扫描设备。
区域分类(区域采用边界定义,即区域边界上与边界外的象素取相同值,区域内部的点取不同值)1、四向连通区域:各象素在水平垂直四个方向是边通的。
即从区域内任一点出发,可水平/垂直移动到达区域内任一点。
实验结果运用扫描线算法进行多边形的填充时,截图显示如下:运用扫描线种子算法进行多边形的填充时,截图显示如下:(注:可编辑下载,若有不当之处,请指正,谢谢!)[文档可能无法思考全面,请浏览后下载,另外祝您生活愉快,工作顺利,万事如意!]。
实验2:多边形区域扫描线填充或种子填充
实验2:多边形区域扫描线填充或种子填充计科102 蓝广森 1007300441一、实验目的通过实验,进一步理解和掌握几种常用多边形填充算法的基本原理掌握多边形区域填充算法的基本过程掌握在C/C++环境下用多边形填充算法编程实现指定多边形的填充。
二、实验内容及要求实现多边形区域扫描线填充的有序边表算法,并将实现的算法应用于任意多边形的填充,要求多边形的顶点由键盘输入或鼠标拾取,填充要准确,不能多填也不能少填。
要求掌握边形区域扫描线填充的有序边表算法的基本原理和算法设计,画出算法实现的程序流程图,使用C或者VC++实现算法,并演示。
三、实验原理种子填充算法又称为边界填充算法。
其基本思想是:从多边形区域的一个内点开始,由内向外用给定的颜色画点直到边界为止。
如果边界是以一种颜色指定的,则种子填充算法可逐个像素地处理直到遇到边界颜色为止。
种子填充算法常用四连通域和八连通域技术进行填充操作。
四向连通填充算法:a)种子像素压入栈中;b)如果栈为空,则转e);否则转c);c)弹出一个像素,并将该像素置成填充色;并判断该像素相邻的四连通像素是否为边界色或已经置成多边形的填充色,若不是,则将该像素压入栈;d)转b);e)结束。
扫描线填充算法的基本过程如下:当给定种子点(x,y)时,首先填充种子点所在扫描线上的位于给定区域的一个区段,然后确定与这一区段相连通的上、下两条扫描线上位于给定区域内的区段,并依次保存下来。
反复这个过程,直到填充结束。
区域填充的扫描线算法可由下列四个步骤实现:(1)初始化:堆栈置空。
将种子点(x,y)入栈。
(2)出栈:若栈空则结束。
否则取栈顶元素(x,y),以y作为当前扫描线。
(3)填充并确定种子点所在区段:从种子点(x,y)出发,沿当前扫描线向左、右两个方向填充,直到边界。
分别标记区段的左、右端点坐标为xl和xr。
(4)并确定新的种子点:在区间[xl,xr]中检查与当前扫描线y上、下相邻的两条扫描线上的象素。
多边形边表桶填充
实验一:改进的有效边表算法一.实验目的用鼠标描绘几个顶点,画出多边形,用边表桶的填充算法实现多边形的填充。
二.算法思想在处理一条扫描线时,仅对与它相交的多边形的边(有效边)求交,其次利用扫描线的连贯性,考虑到当前扫描线与各边的交点顺序与下一条扫描线各边的交点顺序很可能相同或者相似,因此在当前扫描线处理完毕之后,不必为下一条扫描线从头开始构造交点信息;最后利用多边形边的连贯性,认为若某条边与当前扫描线相交,则它很可能也与下一条扫描线相交且其交点与上一次的交点相交。
三.实现过程1.边表的构造1.首先构造一个纵向链表,链表长度为多边形所占有的最大扫描线数,链表的每个结点,称为,称为一个桶,对应多边形覆盖的每一条扫描线。
2.将每条边的信息装入与该边最小Y坐标(Ymin)相对应的桶中,也就是说,若某条边的较低端点为Ymin,则该边就放在相应的Y=Ymin的扫描线桶中。
3.每条边的数据形成一个结点,内容包括该扫描线与该边的初始交点X(即较低端点的X坐标),该边的最大Y 坐标值Ymax,以及边斜率的倒数1/k.4.同一桶中若干条边按x|ymin 由小到大排序,若x|ymin相等,则按照1/k由小到大排序。
2.扫描线的填充算法1.初始化。
构造边表,AET表设置为空。
2.将第一个不空的ET表中的边与AET表合并。
3.由AET表中取出的交点并进行填充,填充时候设置一个布尔量b(初值为假),令指针有效边表中的第一个结点(交点)到最后一个结点遍历一次,每访问一个结点,把b取反一次,若b为真,则把从当前结点的x值开始到下一个结点的x值结束的区间用多边形色填充,填充之后删除y=ymax的边(需注意,填充时同样为避免多边形区域的扩大化,需要多交点进行与x-扫面线算法相同的处理)。
4.y i+1=y i+1,根据x i+1=x i+1/k计算并修改AET表,同时合并ET表中y=y i+1桶中的边,按次序插入到AET 表中形成新的AET表。
实验三计算机图形学多边形填充算法
实验三计算机图形学多边形填充算法课程名称计算机图形学实验日期 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// CChildViewCChildView::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); //绘制多边形elseFillPolygon(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();elsereturn;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// CdemoViewIMPLEMENT_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); //计算/kif(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); //置为背景色elsepDC->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); //绘制多边形elseFillPolygon(pDC); //填充多边形ReleaseDC(pDC); //释放DC }// CdemoView 诊断#ifdef _DEBUGvoid 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();elsereturn;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// CdemoViewIMPLEMENT_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 _DEBUGvoid 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 //_DEBUGvoid 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;//内存DCCBitmap NewBitmap, *pOldBitmap; //内存中承载图像的位图MemDC.CreateCompatibleDC(pDC); //建立与屏幕pDC兼容的MemDCNewBitmap.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(); //删除MemDCReleaseDC(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;elsePopPoint.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(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;elsePopPoint.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++;}}delete pHead;pHead = NULL;}void CdemoView::Push(CP2 point)//入栈函数{pTop = new CStackNode;pTop->PixelPoint = point;pTop->pNext = pHead->pNext;pHead->pNext = pTop;}void CdemoView::Pop(CP2 &point) //出栈函数{if(pHead->pNext != NULL){pTop = pHead->pNext;pHead->pNext = pTop->pNext;point = pTop->PixelPoint;delete pTop;}}// CdemoView 消息处理程序void CdemoView::OnLButtonDown(UINT nFlags, CPoint point) {// TODO: 在此添加消息处理程序代码和/或调用默认值Seed = CP2(point.x - rect.Width() / 2, rect.Height() / 2 - point.y); //选择种子位置Invalidate(FALSE);CView::OnLButtonDown(nFlags, point);}void CdemoView::OnDrawPic(){// TODO: 在此添加命令处理程序代码CColorDialog ccd(SeedClr, CC_SOLIDCOLOR);if(IDOK == ccd.DoModal())//调用颜色对话框选取填充色SeedClr = ccd.GetColor();elsereturn;if(IDOK == MessageBox(L"请在空心字体内单击鼠标左键!", L"提示",MB_OKCANCEL))bFill = TRUE;elsereturn;}实验总结:上机做实验主要是看明白程序,现在来说,自己还不会自己编程,还是下载老师的实例程序看代码,然后运行看结果,自己再去琢磨理解程序。
图形学实验报告四 多边形填充算法
扫描线种子填充:
public void FillField(int x, int y, Color newColor, uint oldColor, Graphics g) {
if ("".Equals(txtx.Text) || "".Equals(txty.Text)) { return; } else { x = Convert.ToInt32(txtx.Text); y = Convert.ToInt32(txty.Text); } int xl, xr; bool spanNeedFill; myStack.Clear();
个交点。如右图,对 y=8 的扫描线排序 x 坐标得到的表是(2,4,9,13),然后对交点 2 与 4 之间、9 与 13 之间 的所有象素点进行填充。 边界上的象素:“左闭右开”,“下闭上开”(将左边界和下边界的点算为内部,而将右边界和上边界 算为外部) 顶点:“上开下闭”。
几种特殊情况: 1.扫描线交于一顶点,共享的两条边分另处于扫描线的两边,这时交点只取一个,如扫描线 y=3,该点被填 充一次。2.共享交点的两条边处于扫描线的上方,这时交点取二个,如扫描线 y=1,该点被填充一次。 3.共享交点的两条边处于扫描线的下方,这时交点取 0 个,如扫描线 y=9,无交点,不填充。 4.水平边在算法中不起任何作用,可不考虑。 活性边表(提高效率): 为了减少求交的计算量,要利用一条边与相继的两条扫描线的交点的连贯性。在处理一条扫描线时只对活 性边(与它相交的多边形的边)进行求交运算。把交点按 x 增加方向存在一个链表(活性边表)中。活性边: 与当前扫描线相交的边。 活性边表(AEL) :按交点 x 的增量顺序存放在一个链表中,该链表称作活性边表(AEL) 。
VC++多边形的填充
if(ccd.DoModal()==IDOK)//调用调色板选取前景色
{
GetColor=ccd.GetColor();
}
RedrawWindow();//刷新屏幕
CreatBucket();//初始化桶
Et();//建立边表
PolygonFill();//多边形填充
{
T1=HeadE;
if(T1==NULL)//边表为空,将边表置为TempEdge
{
T1=NewEdge;
HeadE=T1;
}
else
{
while(T1->next!=NULL)//边表不为空,将TempEdge连在该边之后
{
T1=T1->next;
}
T1->next=NewEdge;
}
}
void CTestView::EdgeOrder()//对边表进行排序函数
ASSERT_VALID(pDoc);
pDC->Polygon(Point,7);//绘制多边形
//输出多边形的顶点编号
pDC->TextOut(550,410,"P0");
pDC->TextOut(350,600,"P1");
pDC->TextOut(230,340,"P2");
pDC->TextOut(350,30,"P3");
class CTestView : public CView
{
。。。。。。。。。
public:
void PolygonFill();//上闭下开填充多边形
带孔多边形填充算法
带孔多边形填充算法一. 基本原理用自上而下的每一条水平的扫描线扫描多边形,每一条扫描线被多边形分成几段,每一段要么在多边形内,要么在多边形外。
在内的填充,在外的舍弃。
见图1图1二. 基本算法1. 水平扫描线与线段求交点假定当前扫描线y 与多边形的某一条边的交点x 坐标为x,那么下一条扫描线y-1与该边的交点不必从头算起,只要加上一个增量即可。
设增量为dx,显然dx= -(x1-x0)/(y1-y0) 结果是:若y=y i ,x=x i ,则当y=y i -1时,x=x i -(x1-x0)/(y1-y0)图22. 活性边与活性边表为了提高效率,在处理一条扫描线时,仅对与它相交的多边形的边进行求交运算。
我们把与当前扫描线相交的边称为活性边,并把它们按与扫描线交点x 坐标递增的顺序存放在一个链表中,称此链表为活性边表。
由于边的连贯性(即当某条边与当前扫描线相交时,它很可能也与下一条扫描线相交),以及扫描线的连贯性(当前扫描线与各边的交点顺序与下一条扫描线与各边的交点顺序很可能相同或非常类似),在当前扫描线处理完毕之后,我们不必为下一条扫描线从头开始构造活性边表,而只要对当前扫描线的活性边表稍作修改,即可更新得到下一条扫描线的活性边表。
例如,(见图3)扫描线6的活性边表如下:P 6P 1 →P 6P 5→ P 5P 4 →P 4P 3扫描线4的活性边表如下:P 6P 1→P 4P 3扫描线3的活性边表如下:P 6P 1→P 3P 2 (满足上闭下开的原则)。
扫描线2的活性边表如下:P 1P 2→P 2P 3 (满足上闭下开的原则)。
y-1 (x0,y0) (x1,y1) y dx 1图3 3.Y 桶表为了方便活性边表的建立与更新,我们为每一条扫描线建立一个新边表,存放在该扫描线第一次出现的边。
也就是说,若某边的较高端点为Y max ,则该边就放在扫描线Y max 的新边表中。
这样,当我们按扫描线从大到小顺序处理扫描线时,该边在该扫描线第一次出现。
多边形填充实验
多边形填充实验实验目标:1.窗口对用户"左按键"和"右按键"事件的响应2.实现多边形填充步骤:1.运行VC6.02.创建工程Fill , (工程类型选择:MFC Wizard (.exe) )3. 添加"双击左键"和"单击右键"事件的消息响应(1).选择菜单"View"->"class Wizard"(2)在弹出的窗口里classname: 选择CFillViewMessages: 分别选择WM_LBUTTONDBLCLK , WM_RBUTTONDOWN 然后Add Function4.修改代码:(1) 修改fillview.h文件:在类的定义中,加入如下代码:public:CPoint spt[7];void Floodfill(CPoint s_point, int f_color, int b_color) ;(2)修改fillview.cpp文件修改OnDraw,OnLButtonDblClk,OnRButtonDown的三个函数加入一个函数: Floodfillvoid CFillView::OnDraw(CDC* pDC){CFillDoc* pDoc = GetDocument();ASSERT_VALID(pDoc);CPen newpen(PS_SOLID,1,RGB(255,0,0));CPen *old=pDC->SelectObject(&newpen);pDC->TextOut(20,20,"双击鼠标左键, 出现需填充的多边形");pDC->TextOut(20,50,"进行填充, 需用鼠标右键, 单击多边形内一点, 作为开始填充的种子点");pDC->SelectObject(old);}(2)void CFillView::OnLButtonDblClk(UINT nFlags, CPoint point){// TODO: Add your message handler code here and/or call defaultRedrawWindow();CDC* pDC=GetDC();CPen newpen(PS_SOLID,1,RGB(255,0,0));CPen *old=pDC->SelectObject(&newpen);//多边形各顶点的坐标spt[0]=CPoint(100,100);spt[1]=CPoint(300,100);spt[2]=CPoint(250,250);spt[3]=CPoint(100,250);spt[4]=CPoint(150,200);spt[5]=CPoint(90,180);spt[6]=CPoint(150,150);spt[7]=CPoint(100,100);pDC->Polyline(spt,8); //画多边形pDC->SelectObject(old);ReleaseDC(pDC);CView::OnLButtonDblClk(nFlags, point);}void CFillView::OnRButtonDown(UINT nFlags, CPoint point){// TODO: Add your message handler code here and/or call defaultCView::OnRButtonDown(nFlags, point);int fill=RGB(0,255,0);int boundary=RGB(255,0,0);Floodfill(point, fill, boundary);}/*s_point 为种子点f_color是要填充的颜色, b_color是边界的颜色*/void CFillView::Floodfill(CPoint s_point, int f_color, int b_color) {CWindowDC dc (this);int x,y,p0,pmin,pmax;//求多边形的最大最小值pmin=pmax=spt[0].y;for(int i=1;i<8;i++){if(spt[i].y<pmin) pmin=spt[i].y;if(spt[i].y>pmax) pmax=spt[i].y;}x=s_point.x;y=s_point.y;for(;y<pmax;y++){int current=dc.GetPixel(x,y);while((current!=b_color)&&(current!=f_color)) {dc.SetPixel(x,y,f_color);x++;current=dc.GetPixel(x,y);}x=s_point.x;x--;current=dc.GetPixel(x,y);while((current!=b_color)&&(current!=f_color)) {dc.SetPixel(x,y,f_color);x--;current=dc.GetPixel(x,y);}x=s_point.x;}x=s_point.x;y=s_point.y-1;for(;y>pmin+2;y--){int current=dc.GetPixel(x,y);while((current!=b_color)&&(current!=f_color)) {dc.SetPixel(x,y,f_color);x++;current=dc.GetPixel(x,y);}x=s_point.x;x--;current=dc.GetPixel(x,y);while((current!=b_color)&&(current!=f_color)) {dc.SetPixel(x,y,f_color);x--;current=dc.GetPixel(x,y);}x=s_point.x;}}。
扫描线多边形填充算法例题
扫描线多边形填充算法例题扫描线多边形填充算法是一种常用的计算机图形学算法,用于对多边形进行填充。
下面我将以一个例题来说明该算法的步骤和原理。
假设有一个凸多边形,顶点坐标分别为A(2, 4),B(6, 6),C(8, 4),D(6, 2),E(4, 2)。
现在我们要使用扫描线多边形填充算法对该多边形进行填充。
步骤如下:1. 首先,确定扫描线的范围。
扫描线的范围由多边形的最高点和最低点决定,即在本例中扫描线的范围为y=2到y=6。
2. 从最高点开始,逐行进行扫描线填充。
在本例中,从y=6开始扫描。
3. 对于每一条扫描线,确定与多边形交点的x坐标。
在本例中,对于y=6,与多边形交点的x坐标为x=2和x=6。
4. 将交点按照升序排列,得到交点序列。
在本例中,交点序列为(2, 6),(6, 6)。
5. 根据交点序列,对每一对交点进行填充。
在本例中,对于(2,6)和(6, 6),在扫描线y=6上的像素点进行填充。
6. 继续向下扫描,重复步骤3至步骤5,直到扫描到最低点y=2。
通过以上步骤,我们可以完成对该凸多边形的填充。
需要注意的是,如果多边形是凹多边形,那么在步骤3中,可能会出现多个交点。
此时,需要根据扫描线与多边形的交点个数的奇偶性来确定填充的规则。
扫描线多边形填充算法的原理是通过扫描线与多边形的交点来确定填充的区域。
该算法的优点是简单易懂,适用于凸多边形和简单的凹多边形。
然而,对于复杂的凹多边形,该算法可能会遇到一些困难。
希望以上回答能够满足你的要求。
如果还有其他问题,请随时提出。
多边形的填充实验经典
试验实验一:图形的区域填充一、实验目的区域填充是指先将区域内的一点(常称为种子点)赋予给定颜色,然后将这种颜色扩展到整个区域内的过程。
区域填充技术广泛应用于交互式图形、动画和美术画的计算机辅助制作中。
本实验采用递归填充算法或打描线算法实现对光栅图形的区域填充。
通过本实验,可以掌握光栅图形编程的基本原理和方法。
实验内容掌握光栅图形的表示方法,实现种子算法或扫描线算法。
通过程序设计实现上述算法。
建议采用VC++实现OpenGL程序设计。
三、实验原理、方法和手段递归算法在要填充的区域内取一点(X, Y)的当前颜色记为oldcoloo用要填充的颜色ne wcolor去取代,递归函数如下:procedure flood-fill(XXoldcoloLnewcolor:integer); beginif getpixel(fiainebufier,x,y)=oldcolorthen beginsetpixel(fiamebuffer,x,y,newcolor); flood-fill(X.Y+1 .oldcoloLiiewcolor);flood-fill(X.Y^ 1 ,oldcoloi;newcolor); flood-fill(X-l,Y;oldcoloi;newcolor); flood-fill(X+l,Yoldcoloi;newcolor);endend扫描线算法扫描线算法的效率明显高于递归算法,其算法的基本思想如下:(1)(初始化)将算法设置的堆栈置为空,将给定的种子点(x,y)压入堆栈。
(2)(出栈)如果堆栈为空,算法结束;否则取栈顶元素(x,y)作为种子点。
(3)(区段填充)从种子点(x,y)开始沿纵坐标为y的当前扫描线向左右两个方向逐个象素进行填色,其值置为newcoloi;直到抵达边界为止。
(4)(定范围)以XleA和Xn血分别表示在步骤3中填充的区段两端点的横坐标。
(5)(进栈)分别在与当前扫描线相邻的上下两条打描线上,确定位于区间[Xldb Xn 曲]内的给定区域的区段。
多边形填充算法实验报告
学生实验报告
实验课名称:计算机图形学
实验项目名称:多边形填充算法
专业名称:计算机科学与技术
班级:
学号:
学生姓名:
教师姓名:
2016年4月30 日
六.运行结果与分析:
图1:扫描线种子填充算法
图2:种子填充算法
七.实验中遇到的问题、解决方法及体会:
多边形的填充对我来说很困难,因为一开始我不知道要输入什么数据,后来我决定要输入五个点来形成一个五边形,但是输入的顺序是一个大问题。
后来我采取顺序输入的方法,但是程序运行时常常崩溃,结果不尽人意。
最后,我在同班同学的帮助之下,找到了自己的问题,完成了填充。
《计算机图形学教学资料》第6讲-多边形填充
05
多边形填充的未来发展
新型填充算法的研究
基于物理的填充算法
模拟真实世界的物理现象,如流体动 力学、表面张力等,以实现更加自然 的多边形填充效果。
智能优化算法
利用遗传算法、模拟退火等智能优化 技术,自动寻找最优的填充方案,提 高填充效率和准确性。
人工智能在多边形填充中的应用
学习型填充算法
通过机器学习技术,让算法自动学习优秀的人类设计师的填充风格,实现更加 艺术化的多边形填充效果。
优化内存管理
合理分配和释放内存,避免频繁的内 存分配和释放操作,可以提高多边形 填充的性能。
04
多边形填充的实践案例
使用OpenGL实现多边形填充
总结词
使用OpenGL进行多边形填充是一种常见的图形编程实践,它涉及到顶点数据、着色器程序和渲染流程的配置。
详细描述
首先,你需要定义多边形的顶点坐标,并将其存储在一个顶点数组中。然后,你需要编写一个OpenGL着色器程 序,用于处理顶点数据并进行渲染。在渲染过程中,你需要设置正确的顶点属性、着色器程序和渲染流程,以确 保多边形能够正确填充颜色。
填充区域
填充区域指的是多边形的内部区域,即所有被填充 的像素组成的区域。
填充颜色
填充颜色是指用于填充多边形内部的颜色,可以根 据需要选择不同的颜色。
填充算法的分类
扫描线填充算法
扫描线填充算法是一种基于扫 描线的填充算法,通过从左到 右、从上到下扫描多边形的内 部像素,对落在多边形内部的 扫描线进行上色。
在游戏开发中应用多边形填充
总结词
在游戏开发中应用多边形填充技术可以创建 更加逼真的游戏场景和角色模型。
详细描述
游戏开发者通常使用游戏引擎(如Unity或 Unreal Engine)来创建游戏场景和角色模 型。在这些引擎中,多边形填充技术被广泛 应用,以实现更加逼真的场景和角色模型。 通过合理配置顶点数据、着色器程序和渲染 流程,游戏开发者可以创建出令人惊叹的游 戏视觉效果。
多边形的边缘填充算法
多边形的边缘填充算法1.实验目的:在一个区域的内部填上不同的灰度或色彩2试验步骤:实验基本思想:逐边向右求补。
可以按任意顺序处理多边形的每条边。
在处理每条边时,首先求出该边与扫描线的交点,然后将每一条扫描线上交点右方的所有像素取补。
多边形的所有边处理完毕之后,填充即完成。
3实验程序(算法思想):1、找出扫描线的范围2、建立边角桶(1)建立空桶(2)遍历多边形各边,根据边的r较小端输入桶中。
3、扫描填充#include "ggltools.h"void gltRasterText(double x, double y, const char *text, void *font){if(text == NULL) return ;glRasterPos2d(x, y);for(int i=0; text[i] != '\0'; i++){glutBitmapCharacter(font, text[i]);}}void gltLine2d(double x0, double y0, double x1, double y1){glBegin(GL_LINES);glVertex2d(x0, y0);glVertex2d(x1, y1);glEnd();}void gltRect2d(double x0, double y0, double x1, double y1)glBegin(GL_LINE_STRIP);glVertex2d(x0, y0);glVertex2d(x1, y0);glVertex2d(x1, y1);glVertex2d(x0, y1);glVertex2d(x0, y0);glEnd();}char gltClipCode(const GPoint2d &pt, const GPoint2d &top, const GPoint2d &bottom) {char code = 0;if(pt.y() > top.y()) code |= 0x01;else if(pt.y() < bottom.y()) code |= 0x02;if(pt.x() > bottom.x()) code |= 0x04;else if(pt.x() < top.x()) code |= 0x08;return code;}template <class T>void swap(T &a , T &b){T t =a;a=b;b=t;}bool gltLineClip2d(GPoint2d &pt0, GPoint2d &pt1,const GPoint2d &top, const GPoint2d &bottom){char c0,c1;double x,y;while (true){c0=gltClipCode(pt0,top,bottom);c1=gltClipCode(pt1,top,bottom);if (c0 & c1) return false;if (c0==0&&c1==0)return true;if(c0==0){swap(pt0,pt1);swap(c0,c1);}if(c0 & 0x01)//点在yt 上方;{y=top.y();x=pt0.x()+(y-pt0.y())*(pt1.x()-pt0.x())/(pt1.y()-pt0.y());}else if (c0 & 0x02){y=bottom.y();x=pt0.x()+(y-pt0.y())*(pt1.x()-pt0.x())/(pt1.y()-pt0.y());}else if(c0 & 0x04){x=bottom.x();y=pt0.y()+(x-pt0.x())*(pt1.y()-pt0.y())/(pt1.x()-pt0.x());}else if(c0 & 0x08){x=top.x();y=pt0.y()+(x-pt0.x())*(pt1.y()-pt0.y())/(pt1.x()-pt0.x());}pt0.set(x,y);}return false;}4.实验输出结果:。
MFC多边形填充
实验5 多边形区域扫描线填充一、实验目的和要求通过本次实验要求学生掌握多边形区域扫描线填充的有序边表算法的基本原理和算法设计。
要求画出算法实现的程序流程图,使用VC++实现算法,并演示。
二、实验主要内容实现多边形区域扫描线填充的有序边表算法,设计相关的数据结构(如链表结构、结点结构等),并将实现的算法应用于任意多边形的填充,注意多边形的顶点应由键盘输入或鼠标拾取,填充要准确,不能多填也不能少填。
三、参考实验步骤1)分析多边形区域扫描线填充算法的原理,确定算法流程①初始化:构造边表,AET表置空②将第一个不空的ET表中的边插入AET表③由AET表取出交点进行配对(奇偶)获得填充区间,依次对这些填充区间着色④y=y i+1时,根据x=x i+1/k修改AET表所有结点中交点的x坐标。
同时如果相应的ET表不空,则将其中的结点插入AET表,形成新的AET表⑤AET表不空,则转(3),否则结束。
2)编程实现①首先确定多边形顶点和ET/AET表中结点的结构②编写链表相关操作(如链表结点插入、删除和排序等)③根据1)中的算法结合上述已有的链表操作函数实现多边形区域扫描线填充的主体功能④编写主函数,测试该算法参考程序void CFillView::OnDraw(CDC* pDC){CFillDoc* pDoc = GetDocument();ASSERT_V ALID(pDoc);POINT pt[5]={{225,10},{155,200},{330,55},{120,55},{295,200}};CBrush brush(HS_DIAGCROSS,RGB(255,0,0)); /*设置填充的样式和颜色*/CBrush* oldbrush=pDC->SelectObject(&brush);pDC->SetPolyFillMode(WINDING); /*选择填充模式*/pDC->Polygon(pt,5); /*画五角星并填充图形*/pDC->SelectObject(oldbrush);POINT pt1[4]={{200,300},{500,300},{500,500},{200,500}};CBrush brush1(HS_CROSS,RGB(255,0,0)); /*设置填充的样式和颜色*/CBrush* oldbrush1=pDC->SelectObject(&brush1);pDC->Polygon(pt1,4); /*画矩形并填充图形*/pDC->SelectObject(oldbrush);brush.DeleteObject();// TODO: add draw code for native data here}(该函数为主函数,其余代码均为MFC自动生成,这就是画图函数)/////////////////////////////////////////////////////////////////////////////// CFillView printingBOOL CFillView::OnPreparePrinting(CPrintInfo* pInfo){// default preparationreturn DoPreparePrinting(pInfo);}#include "stdafx.h"#include "fill.h"#include "fillDoc.h"#include "fillView.h"#ifdef _DEBUG#define new DEBUG_NEW#undef THIS_FILEstatic char THIS_FILE[] = __FILE__;#endif/////////////////////////////////////////////////////////////////////////////// CFillViewIMPLEMENT_DYNCREATE(CFillView, CView)BEGIN_MESSAGE_MAP(CFillView, CView)//{{AFX_MSG_MAP(CFillView)// NOTE - the ClassWizard will add and remove mapping macros here.// DO NOT EDIT what you see in these blocks of generated code!//}}AFX_MSG_MAP// Standard printing commandsON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview) END_MESSAGE_MAP()/////////////////////////////////////////////////////////////////////////////// CFillView construction/destructionCFillView::CFillView(){// TODO: add construction code here}CFillView::~CFillView(){}BOOL CFillView::PreCreateWindow(CREATESTRUCT& cs){// TODO: Modify the Window class or styles here by modifying// the CREATESTRUCT csreturn CView::PreCreateWindow(cs);}/////////////////////////////////////////////////////////////////////////////// CFillView drawingvoid CFillView::OnDraw(CDC* pDC){CFillDoc* pDoc = GetDocument();ASSERT_V ALID(pDoc);POINT pt[5]={{225,10},{155,200},{330,55},{120,55},{295,200}};CBrush brush(HS_DIAGCROSS,RGB(255,0,0)); /*设置填充的样式和颜色*/ CBrush* oldbrush=pDC->SelectObject(&brush);pDC->SetPolyFillMode(WINDING); /*选择填充模式*/pDC->Polygon(pt,5); /*画五角星并填充图形*/pDC->SelectObject(oldbrush);POINT pt1[4]={{200,300},{500,300},{500,500},{200,500}};CBrush brush1(HS_CROSS,RGB(255,0,0)); /*设置填充的样式和颜色*/CBrush* oldbrush1=pDC->SelectObject(&brush1);pDC->Polygon(pt1,4); /*画矩形并填充图形*/pDC->SelectObject(oldbrush);brush.DeleteObject();// TODO: add draw code for native data here}/////////////////////////////////////////////////////////////////////////////// CFillView printingBOOL CFillView::OnPreparePrinting(CPrintInfo* pInfo){// default preparationreturn DoPreparePrinting(pInfo);}void CFillView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) {// TODO: add extra initialization before printing}void CFillView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) {// TODO: add cleanup after printing}/////////////////////////////////////////////////////////////////////////////// CFillView diagnostics#ifdef _DEBUGvoid CFillView::AssertValid() const{CView::AssertValid();}void CFillView::Dump(CDumpContext& dc) const{CView::Dump(dc);}CFillDoc* CFillView::GetDocument() // non-debug version is inline{ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CFillDoc)));return (CFillDoc*)m_pDocument;}#endif //_DEBUG。
计算机图形学-实验报告2-多边形有效边表填充算法
(9)如果甬结点的扫描线值大于等于有效边表中的结点值ymax,则该边为无效边。
(10)当甬结点不为空则转(6)否则删除甬表和边表的头结点,算法结束。
(11)实验结果及分析:
实验地点
软件实验室
指导教师
(3)动态链表的排序算法
二、实验内容:
三、自定义屏幕二维坐标系,原点位于客户区中心,x轴水平向右为正,y轴垂直向上为正。
四、在屏幕客户区内使用cline类绘制示例多边形边界。
五、设置屏幕背景色为白死,调用windows的颜色对话框选择填充色使用单一颜色填充多边形。
六、使用有效边表填充算法填充示例多边形内部及边界。
(5)对每个甬结点链接的边表,根据x|ymin值的大小进行排序,若x|ymin相等,则按照k由小到大排序。
(6)循环访问每个甬结点,将甬内每个结点的边表合并成有效边表,并循环访问有限边表。
(7)从有效边表中取出扫描线上相邻两条边的结点对进行配对。填充时设置一个逻辑变量binflag,每访问一个结点,把binflag值取反一次,若binflag为真,则把从当前结点的x值开始到下一结点x值结束的区间用指定的颜色填充。
七、实验步骤:
(1)调用颜色对话框读取填充色。
(2)根据示例多边形顶点坐标值,计算扫描线的最大值ScanMax和最小值ScanMin。
(3)用多边形覆盖的扫描线动态建立甬结点。
(4)循环访问多边形的所有顶点,根据边的顶点y值比起点y值高或边的终点y值比起点y值低两种情况,计算每条边的ymin。在甬中寻找与该ymin相对应的甬结点计算该边表示的x|ymin,ymax,k,并依据次链接该边表结点到甬结点。
3多边形的填充
实验三、多边形的填充一 .实验要求和目的1)认识多边形扫描转换,认识并掌握逐点判断算法,扫描线算法,边界标志算法等的实现及优缺点。
2)理解什么是四连通区域和八连通区域。
理解并掌握一种多边形填充的原来及其实现。
二.实验原理:扫描线种子填充算法:原理:给定种子点),(yx时,首先填充种子点所在扫描线上的位于给定区域的一个区段,然后确定与这一区域相连通的上下扫描线上位于给定区域内的区段,并保存下来,直到填充结束。
三.实验环境(1)硬件:PC机;⑵软件:Windows7操作系统、Visual Studio2010。
四、相关代码void CgraphicsView::drawFill(){mflags=4;beginpoint=(0,0);endpoint=(0,0);RedrawWindow();CDC* pDC=GetDC();CPen newpen(PS_SOLID,1,RGB(0,0,0));CPen *oldpen=pDC->SelectObject(&newpen);spt[0]=CPoint(100,100);spt[1]=CPoint(100,300);spt[2]=CPoint(250,250);spt[3]=CPoint(250,100);spt[4]=CPoint(200,150);spt[5]=CPoint(180,90);spt[6]=CPoint(150,150);spt[7]=CPoint(100,100);pDC->Polyline(spt, 8);pDC->SelectObject(oldpen);ReleaseDC(pDC);}五、实验截图六、总结通过本次实验我掌握了扫描线种子填充算法,掌握了逐点判断算法,扫描线算法,边界标志算法等的实现及优缺点。
Ch543多边形区域填充-39页文档资料
345612YTU610 3 10 14 8
16 17
11
12 13 14 15
10
7 8 9 10 11
3456
3
1
2
10
14
8
YTU
YTU
☆Flash演示 8 连通泛填充算法
对比
边界填充算法
(1)栈顶像素出栈; (2)将出栈像素置成填充
色; (3)检查出栈像素的
4-邻接点, 若其中某个像素点 不是边界色 且未置成填充色, 则把该像素入栈。
若其中某个像素点
不是边界色 且 未置成填充色,
则把该像素入栈。
种子像素入栈
0
YTU
1 2
YTU
B AC
D
2 1
入栈条件:
不是边界色 且未置成填 充色
13 4
5
YTU
5 4 3 1
不是边界 色且未置 成填充色
13 4
YTU
4 3 1
不是边界 色且未置 成填充色
6
136
3
1
不是边界
色且未置
YTU
YTU
5.4.3 区域填充
区域 点阵形式的填充图形,是像素的集合
区域的表示
边界表示法 内点表示
区域填充算法
边界填充算法 泛填充算法
YTU
区域的表示
边界表示
内点表示
YTU
区域填充算法 - 种子填充算法
种子
YTU
问题
区域填充算法要求区域一定是__连__通__的
YTU
4连通区域 和 8连通区域
YTU
小结 算法步骤
初始: 种子入栈 栈顶元素出栈
填充该元素 填充该元素所在扫描线
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
num = 0;
col = RGB(0,0,0);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if(pSysMenu != NULL)
{
CString ing(IDS_ABOUTBOX);
if(!strAboutMenu.IsEmpty())
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE);// Set big icon
SetIcon(m_hIcon, FALSE);// Set small icon
// TODO: Add extra initialization here
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// Set the icon for this dialog. The framework does this automatically
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CMyDlg, CDialog)
//{{AFX_MSG_MAP(CMyDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_BUTTON4, OnButton4)
//}}AFX_DATA_INIT
}
voidCAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CAboutDlg)
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
//
#include"stdafx.h"
#include"填充.h"
#include"填充Dlg.h"
#ifdef_DEBUG
#definenewDEBUG_NEW
#undefTHIS_FILE
staticcharTHIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
(3)(区段填充)从种子点(x,y)开始沿纵坐标为y的当前扫描线向左右两个方向逐个象素进行填色,其值置为newcolor,直到抵达边界为止。
(4)(定范围)以xleft和xright分别表示在步骤3中填充的区段两端点的横坐标。
(5)(进栈)分别在与当前扫描线相邻的上下两条扫描线上,确定位于区间[xleft,xright]内的给定区域的区段。如果这些区段内的象素的颜色值为newcolor或者boundarycolor(边界上象素的颜色值),则转到步骤2,否则取区段的右端点为种子压入堆栈,再转到步骤2继续执行。
mdc.CreateCompatibleDC(GetDC());
ob = mdc.SelectObject(&bp);
mdc.BitBlt(0,0,520,330,&pic,0,0,SRCCOPY);
mdc.MoveTo(mx[0],my[0]);
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CMyDlg message handlers
BOOL CMyDlg::OnInitDialog()
掌握光栅图形的表示方法,实现种子算法或扫描线算法。通过程序设计实现上述算法。建议采用VC++实现OpenGL程序设计。
三、实验原理、方法和手段
递归算法
在要填充的区域内取一点(X,Y)的当前颜色记为oldcolor,用要填充的颜色newcolor去取代,递归函数如下:
procedureflood-fill(X,Y,oldcolor,newcolor:integer);
inty = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
}
CDC mdc;
CBitmap bp,*ob;
bp.LoadBitmap(IDB_B);
flood-fill(X-1,Y,oldcolor,newcolor);
flood-fill(X+1,Y,oldcolor,newcolor);
end
end
扫描线算法
扫描线算法的效率明显高于递归算法,其算法的基本思想如下:
(1)(初始化)将算法设置的堆栈置为空,将给定的种子点(x,y)压入堆栈。
(2)(出栈)如果堆栈为空,算法结束;否则取栈顶元素(x,y)作为种子点。
// this is automatically done for you by the framework.
voidCMyDlg::OnPaint()
{
CPaintDC dc(this);// device context for painting
if(IsIconic())
{
SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
// CMyDlg dialog
CMyDlg::CMyDlg(CWnd* pParent/*=NULL*/)
: CDialog(CMyDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CMyDlg)
// NOTE: the ClassWizard will add member initialization here
ON_BN_CLICKED(IDC_BUTTON1, OnButton1)
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_WM_MOUSEMOVE()
ON_BN_CLICKED(IDC_BUTTON2, OnButton2)
ON_BN_CLICKED(IDC_BUTTON3, OnButton3)
{
CDialog::OnInitDialog();
// Add "About..." menu item to system menu.
// IDM_ABOUTBOX must be in the system command range.
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
//}}AFX_VIRTUAL
// Implementation
protected:
//{{AFX_MSG(CAboutDlg)
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
//{{AFX_DATA_INIT(CAboutDlg)
// CAboutDlg dialog used for App About
classCAboutDlg :publicCDialog
{
public:
CAboutDlg();
// Dialog Data
//{{AFX_DATA(CAboutDlg)
enum{ IDD = IDD_ABOUTBOX };
returnTRUE;// return TRUE unless you set the focus to a control
}
voidCMyDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
CPaintDC dc(this);
pic.CreateCompatibleDC(&dc);
CBitmap * bp1,*obp1;
bp1 =newCBitmap;
bp1->LoadBitmap(IDB_B);
obp1 = pic.SelectObject(bp1);
obp1->DeleteObject();
// Center icon in client rectangle
intcxIcon = GetSystemMetrics(SM_CXICON);
intcyIcon = GetSystemMetrics(SM_CYICON);