MFC多边形填充

合集下载

实验三计算机图形学多边形填充算法

实验三计算机图形学多边形填充算法

实验三计算机图形学多边形填充算法课程名称计算机图形学实验日期 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;}实验总结:上机做实验主要是看明白程序,现在来说,自己还不会自己编程,还是下载老师的实例程序看代码,然后运行看结果,自己再去琢磨理解程序。

c语言多边形区域填充算法

c语言多边形区域填充算法

c语言多边形区域填充算法C语言多边形区域填充算法一、介绍多边形区域填充算法是计算机图形学中的一项重要技术,用于将给定的多边形区域进行填充,使其呈现出丰富的颜色或纹理,增强图形的效果和表现力。

本文将介绍一种常用的C语言多边形区域填充算法——扫描线填充算法。

二、扫描线填充算法原理扫描线填充算法是一种基于扫描线的填充方法,其基本思想是将多边形区域按照水平扫描线的顺序,从上到下逐行扫描,通过判断扫描线与多边形边界的交点个数来确定是否进入多边形区域。

具体步骤如下:1. 首先,确定多边形的边界,将其存储为一个边表。

边表中的每个边都包含起点和终点的坐标。

2. 创建一个活性边表(AET),用于存储当前扫描线与多边形边界的交点。

初始时,AET为空。

3. 从上到下逐行扫描多边形区域,对每一条扫描线,从边表中找出与该扫描线相交的边,并将其加入AET中。

4. 对于AET中的每一对交点,按照从左到右的顺序两两配对,形成水平线段,将其填充为指定的颜色或纹理。

5. 在扫描线的下一行,更新AET中的交点的坐标,然后重复步骤4,直到扫描到多边形区域的底部。

三、代码实现下面是一个简单的C语言实现扫描线填充算法的示例代码:```#include <stdio.h>#include <stdlib.h>#include <stdbool.h>typedef struct {int x;int y;} Point;typedef struct {int yMax;float x;float dx;int next;} Edge;void fillPolygon(int n, Point* points, int color) {// 获取多边形的边界int yMin = points[0].y;int yMax = points[0].y;for (int i = 1; i < n; i++) {if (points[i].y < yMin) {yMin = points[i].y;}if (points[i].y > yMax) {yMax = points[i].y;}}// 创建边表Edge* edges = (Edge*)malloc(sizeof(Edge) * n);int k = n - 1;for (int i = 0; i < n; i++) {if (points[i].y < points[k].y) {edges[i].yMax = points[k].y;edges[i].x = points[i].x;edges[i].dx = (float)(points[k].x - points[i].x) / (points[k].y - points[i].y);edges[i].next = k;} else {edges[i].yMax = points[i].y;edges[i].x = points[k].x;edges[i].dx = (float)(points[i].x - points[k].x) / (points[i].y - points[k].y);edges[i].next = i;}k = i;}// 扫描线填充for (int y = yMin; y < yMax; y++) {int xMin = INT_MAX;int xMax = INT_MIN;for (int i = 0; i < n; i++) {if (y >= edges[i].yMax) {continue;}edges[i].x += edges[i].dx;if (edges[i].x < xMin) {xMin = edges[i].x;}if (edges[i].x > xMax) {xMax = edges[i].x;}int j = edges[i].next;while (j != i) {edges[j].x += edges[j].dx; if (edges[j].x < xMin) {xMin = edges[j].x;}if (edges[j].x > xMax) {xMax = edges[j].x;}j = edges[j].next;}}for (int x = xMin; x < xMax; x++) { drawPixel(x, y, color);}}free(edges);}int main() {// 定义多边形的顶点坐标Point points[] = {{100, 100},{200, 200},{300, 150},{250, 100}};// 填充多边形区域为红色fillPolygon(4, points, RED);return 0;}```四、总结通过扫描线填充算法,我们可以实现对多边形区域的填充,从而提升图形的表现效果。

实验三计算机图形学多边形填充算法

实验三计算机图形学多边形填充算法

实验三计算机图形学多边形填充算法课程名称计算机图形学实验日期 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;}实验总结:上机做实验主要是看明白程序,现在来说,自己还不会自己编程,还是下载老师的实例程序看代码,然后运行看结果,自己再去琢磨理解程序。

多边形扫描线填充算法技巧

多边形扫描线填充算法技巧

多边形扫描线填充算法技巧扫描线填充算法是计算机图形学中常用的一种填充算法,用于对多边形进行填充。

其基本原理是通过扫描线与多边形边界的交点来确定需要填充的像素点。

本文将介绍多边形扫描线填充算法的基本思想以及一些常用的优化技巧。

一、基本思想多边形扫描线填充算法的基本思想是将多边形分解成一系列水平线段,然后对每条水平线段进行扫描,找出与多边形边界相交的点,并进行填充。

具体步骤如下:1. 确定多边形的边界:对于给定的多边形,首先需要确定其边界。

可以使用边界表(edge table)来存储多边形的边界信息,包括每条边的起点和终点坐标以及斜率等。

2. 初始化扫描线:从多边形边界中找出最小的y坐标和最大的y坐标,作为扫描线的起点和终点。

3. 扫描线算法:对于每条扫描线,通过遍历边界表,找出与扫描线相交的边界线段。

根据相交点的x坐标,确定需要填充的像素点范围。

4. 填充像素点:根据上一步确定的像素点范围,将扫描线上的像素点进行填充。

二、技巧和优化1. 边界表的构建:为了提高算法的效率,可以对边界表进行排序,按照扫描线的y坐标来排序。

这样可以减少对边界表的遍历次数,提高算法的执行速度。

2. 边界交点的计算:在扫描线算法中,需要计算扫描线与多边形边界的交点。

可以使用活性边表(active edge table)来存储当前与扫描线相交的边界线段,并根据交点的x坐标进行排序。

这样可以减少计算交点的次数,提高算法的效率。

3. 填充像素点的优化:在填充像素点时,可以使用扫描线种子填充算法来进行优化。

该算法通过选择合适的填充起点,在填充过程中自动推进扫描线,减少不必要的计算和填充操作,提高填充的速度。

4. 填充规则的处理:在实际应用中,可能会遇到一些特殊情况,如多边形内部有孔洞或交叉等。

针对这些情况,可以通过修改填充规则来处理。

常用的填充规则有奇偶填充规则和非零填充规则,可以根据实际情况选择合适的填充规则。

5. 像素点颜色的处理:在多边形填充过程中,可以通过设置填充的颜色或纹理来实现不同的效果。

计算机图形学基础教程(Visual C++版)第04章 多边形填充(清华大学出版社 孔令德)

计算机图形学基础教程(Visual C++版)第04章 多边形填充(清华大学出版社 孔令德)

⑵点阵表示法
用多边形覆盖的像素点集来描述 特点是便于直接确定实面积图形覆盖的像素点,是多 边形填充所需要的表示形式, 但是缺少了多边形顶点的几何信息。
⑶多边形的扫描转换
将多边形的描述从顶点表示法变换到 点阵表示法的过程,称为多边形的扫描 转换。 即从多边形的顶点信息出发,求出多 边形内部的各个像素点信息。
4.2 有效边表填充算法
4.2.1 填充原理 4.2.2 有效边和有效边表 4.2.3 边表

4.2.1 填充原理



为了计算每条扫描线与多边形各边的交点, 最简单的方法是把多边形的所有边放在一个 表中。 处理每条扫描线时,按顺序从表中取出所有 边,分别与扫描线求交点。 缺点:效率不高 重复判别多
P2P3 S=1 3 7
P0(7,8),P1(3,12) P2(1,7),P3(3,1) P4(6,5), P5(8,1) P6(12,9)
P4P5 8 5 -1/2 8 9
P5 P6 1/2
10 9 8 7 6 5 4 3 2 1
P0 P2 P4
P6
P3
1 2 3 4 5 6 7 8 9
P5
10 11 12 13 x
如图4-11所示,随着扫描 线的移动,扫描线与有效边 交点的x坐标从起点开始可 以按增量1/k计算出来。
(xi,yi) 1/k
(xi+1,yi+1)
图4-11 有效边交点相关性
2.有效边表(Active
Edge Table,AET)
把有效边按照与扫描线交点x坐标递增的 顺序存放在一个链表中,称为有效边表 有效边表的结点:
P4P5 7 5 -1/2 9 9
P5 P6 1/2

多边形填充算法

多边形填充算法

多边形填充算法
多边形填充算法是一种计算机图形学中的算法,用于将一个封闭的多边形区域(如矩形、三角形、梯形等)填充成指定的颜色。

在计算机图形学中,多边形是由一系列线段(边)连接成的封闭区域。

填充算法的目的是在多边形的内部填充指定的颜色。

这种算法通常用于计算机辅助设计、计算机游戏开发、计算机动画、计算机视觉等领域。

填充算法有多种实现方法,包括扫描线填充、种子填充、边界填充、区域分割等。

其中,扫描线填充是最常见的一种算法,它的基本思想是从多边形的最上面一行开始,逐行向下扫描,同时记录扫描线和多边形之间的交点。

当扫描线与多边形的边相交时,根据交点的奇偶性来判断该点是否在多边形内部。

如果是奇数个交点,则该点在多边形内部,需要进行填充;如果是偶数个交点,则该点在多边形外部,不需要填充。

种子填充是另一种常见的填充算法,它的基本思想是从多边形内部的一个点(种子)开始,向外扩散填充。

在扩散过程中,同时记录已经填充过的像素点,避免重复填充。

这种算法的优点是填充速度较快,但容易出现填充区域不封闭、填充效果不理想等问题。

边界填充和区域分割是另外两种填充算法,它们的实现方式比较复杂,但可以处
理比较复杂的填充情况,例如多个子多边形共同填充、奇异多边形填充等。

总的来说,多边形填充算法在计算机图形学中具有重要的应用价值和研究意义,不同的填充算法各有优缺点,需要根据具体的需求和应用场景来选择合适的算法。

多边形的有效边表填充算法

多边形的有效边表填充算法

实验三多边形的有效边表填充算法一、实验目的与要求1、理解多边形的扫描转换原理、方法;2、掌握有效边表填充算法;3、掌握链表的建立、添加结点、删除节点的基本方法;3、掌握基于链表的排序操作。

二、实验内容在实验二所实现工程的基础上,实现以下内容并把实现函数封装在类CMyGL 中。

1、C++实现有效边表算法进行多边形扫描转换2、利用1进行多边形扫描转换和区域填充的实现;三、实验原理请同学们根据教材及上课的PPT独立完成。

四、实验步骤(程序实现)。

1、建立并选择工程项目。

打开VC6.0->菜单File 的New 项,在projects 属性页选择MFC AppWizard(exe)项,在Project name 中输入一个工程名,如“Sample”。

单文档。

2、新建一个图形类。

选择菜单InsertNew class,Class type 选择“Generic Class”,Name 输入类名,如“CMyCG。

3、向新建的图形类中添加成员函数(实际就是加入实验要求实现的图形生成算法的实现代码)。

在工作区中直接鼠标右键单击,选择“Add Member Function…”项,添加绘制圆的成员函数。

void PolygonFill(int number, CPoint *p, COLORREF color, CDC* pDC)添加其他成员函数:CreatBucket();CreatET();AddEdge();EdgeOrder();4、成员函数的实现。

实现有效边表填充算法。

这一部分需要同学们去实现。

参考实现:多边形的有效边表填充算法的基本过程为:1、定义多边形:2、初始化桶3、建立边表4、多边形填充1)对每一条扫描线,将该扫描线上的边结点插入到临时AET表中,HeadE.2)对临时AET表排序,按照x递增的顺序存放。

3)根据AET表中边表结点的ymax抛弃扫描完的边结点,即ymax>=scanline4)扫描AET表,填充扫描线和多边形相交的区间。

基于MFC和OpenGL的快速填充等值线实现

基于MFC和OpenGL的快速填充等值线实现

基于M FC和OpenGL的快速填充等值线实现孙晓燕1,伍增贵2(1.石油大学计算机与通信工程学院,山东东营257061;2.石油大学石油工程学院,山东东营257061)摘 要:通过等值线的绘制与填充过程分离的编程思想,先用OpenG L硬件加速的光栅化技术实现区域快速填充,然后利用MFC下的G D I绘图功能在相同的区域上绘制等值线。

该方法不涉及到复杂的算法,用很简单的代码就能实现与商业软件视觉效果相媲美的等值线填充效果,且适用于离散区域为任意形状的多边形网格系统。

关键词:等值线填充;OpenG L;可视化;MFC;调色板中图法分类号:TP391141 文献标识码:A 文章编号:100123695(2005)0320169202 Realizati on of Fast Filling Cont ours Based on MFC and OpenG LS UN Xiao2yan1,WU Zeng2gui2(1.College of Co m puter&Co mm unication Engineering,U niversity of Petroleum(East China),D ongying Shandong257061,China;2.College of Petroleum Engineering,U niversity of Petroleum(East China),D ongying Shandong257061,China)Abstract:This paper p resents a p r ogra mm ing idea of dra wing and filling cont ours res pectively.First the zone is filled by ta2 king advantage of rap id raster dis p lay of OpenG L,then on the sa me zone cont ourlines are generated by using G D I functi ons of MFC.W ithout any comp licated algorith m,the p r ogra m is easily realized,but p r ovides excellent visual effects comparable with commercial s oft w are.I n additi on,the method can be app lied t o vari ous grid syste m s.Key words:Cont ours Fill;OpenG L;V isualizati on;M FC;Palette 在工程计算分析中常常涉及到大量的参数场,如温度场、压力场、浓度场、速度场、应力场等数据场的分析和处理。

多边形填充算法本

多边形填充算法本

多边形填充算法本在计算机图形学中,使用多边形填充算法可以实现各种图形的绘制,例如:圆形、椭圆形、字母等。

对于任意形状的多边形来说,其内部像素点的坐标是无法直接计算得到的,因此需要通过一定的算法来实现。

常见的多边形填充算法有扫描线填充算法和边界填充算法。

接下来我们来详细了解这两种算法。

扫描线填充算法是通过扫描多边形上的每一条水平线,找到与多边形相交的线段,并进行填充操作。

具体步骤如下:1.找到多边形的最高点和最低点,作为扫描线的起点和终点。

2.将扫描线从起点依次向下移动,直到到达终点。

3.在每一条扫描线上,找到与多边形相交的线段。

4.根据线段的起点和终点,计算交点的x坐标,并从起点到终点对应的像素点进行填充。

5.重复步骤4,直到所有的扫描线都处理完毕。

扫描线填充算法的优点是简单易懂,适用于一般情况。

但是对于复杂的多边形来说,会存在边界交叉的情况,需要特殊处理。

边界填充算法是通过检测多边形的边界点,并进行填充操作。

具体步骤如下:1.找到多边形的最左边、最右边、最上边和最下边的点,作为边界点。

2.从最上边的点开始,依次向下遍历每一行像素点。

3.在每一行中,寻找与多边形边界相交的点,并进行填充操作。

4.重复步骤3,直到到达最下边的点。

边界填充算法的优点是对具有复杂交叉边界的多边形也能进行正确的填充操作。

但是对于非凸多边形来说,边界填充算法可能会有空隙出现。

除了以上两种常见的多边形填充算法,还有其他一些算法也可以实现多边形的填充操作,例如:扫描转换填充算法、边界边框填充算法等。

在实际应用中,多边形填充算法通常结合图形处理库或者计算机图形学软件来实现。

这些软件提供了丰富的函数和方法,可以直接调用进行多边形的填充操作。

综上所述,多边形填充算法是计算机图形学中的一个重要算法。

通过扫描线填充算法或者边界填充算法,可以实现对任意形状多边形的填充操作。

随着计算机图形学的发展,多边形填充算法也不断进化和优化,以满足不同应用场景的需求。

多边形填充算法实验报告

多边形填充算法实验报告

学生实验报告
实验课名称:计算机图形学
实验项目名称:多边形填充算法
专业名称:计算机科学与技术
班级:
学号:
学生姓名:
教师姓名:
2016年4月30 日
六.运行结果与分析:
图1:扫描线种子填充算法
图2:种子填充算法
七.实验中遇到的问题、解决方法及体会:
多边形的填充对我来说很困难,因为一开始我不知道要输入什么数据,后来我决定要输入五个点来形成一个五边形,但是输入的顺序是一个大问题。

后来我采取顺序输入的方法,但是程序运行时常常崩溃,结果不尽人意。

最后,我在同班同学的帮助之下,找到了自己的问题,完成了填充。

第4章多边形填充算法

第4章多边形填充算法

E2
E5
E3 E4
边缘填充算法示意图
1.边缘填充算法(正负相消法) 基本原理是:对每一条扫描线,依次求与多边形各边 的交点,将该扫描线上交点右边的所有像素求补。多 边形所有边处理完毕,填充即完成。
优点:简单易行 缺点:多边形外的像素处 理过多,输入输出量大
算法改进
• ቤተ መጻሕፍቲ ባይዱ围盒 • 栅栏
带包围盒的多边形
第4章 多边形填充算法
4.3 边缘填充算法
4.3.1 填充原理
• 求出多边形的每条边与扫描线的交点 • 将交点右侧的所有像素颜色全部取为补
色。 • 按任意顺序处理完多边形的所有边。
4.3.2 填充过程
假定边的访问顺序为E0、E1、E2、E3、E4、E5和E6。
P1(x1,y1)
E1
E0
E6
P0(x0,y0)
缺点:某些像素被重复取补
3.边标志填充算法
基本思想:先用一种特殊的颜色在帧缓存中将多边形 的边界(水平边除外)勾画出来,然后将着色的像素点依x 坐标递增的顺序两两配对,再将每一对像素所构成的扫描线 区间内的所有像素置为填充色。
3.边标志填充算法
①打标记:对多边形边界所在像素置一个特殊标志。按照 “下闭上开”的原则处理局部最低点为两个交点,局部 最高点为0个交点。
② 填充:对于每条与多边形相交的扫描线,依照“左闭 右开”的原则从左至右逐个访问该扫描线上的像素,并 着色。
3.边标志填充算法
栅栏填充算法
栅栏:一条过多边形顶点且与扫描线垂直的直线,它将 多边形分成两半,只要将栅栏与多边形之间的像素求补 即可。
缺点:某些像素被重复取补
栅栏填充算法
基本原理:对于每条扫描线与多边形的交点,将交点与栅栏 之间的扫描线上的像素取补,也就是说,若交点位于栅 栏左边,则将交点之右、栅栏之左的所有像素取补;若 交点位于栅栏右边,则将栅栏之右、交点之左的所有像 素取补。

计算机图形学多边形填充算法

计算机图形学多边形填充算法

计算机图形学多边形填充算法计算机图形学中的多边形填充算法是指将给定的多边形区域进行颜色填充,以使其完全填充的过程。

在图形学中,多边形是由一系列连续的线段组成的封闭图形。

填充算法可用于渲染图形、绘制图像等应用场景。

多边形填充算法的目标是根据设计要求和用户输入,给定一个多边形的边界,将多边形的内部区域进行颜色填充。

填充算法的实现涉及到图像的扫描线和区域判定,以确定填充的区域和颜色。

在本文中,我们将介绍常见的多边形填充算法,包括扫描线填充算法、边界填充算法等,并讨论它们的优缺点和适用场景。

扫描线填充算法扫描线填充算法是一种常见且简单的多边形填充算法。

该算法将多边形划分为一条条水平扫描线,并通过判断扫描线与多边形边界的交点,确定填充区域。

具体步骤如下:1.找到多边形边界的最上端和最下端。

2.从最上端开始,逐行进行扫描。

3.在每一行,通过求解扫描线与多边形边界的交点,确定填充区域。

4.对于每个填充区域,根据设计要求进行颜色填充。

扫描线填充算法的优点是简单易懂、实现较为容易。

然而,该算法存在一些缺点。

首先,对于具有复杂形状的多边形,扫描线填充算法可能会产生很多不必要的计算,导致效率降低。

其次,该算法需要处理多边形边界相交的情况,可能出现像素重复填充的问题,需要进行额外的处理。

边界填充算法边界填充算法是另一种常见的多边形填充算法。

与扫描线填充算法不同的是,边界填充算法是从多边形的边界出发,向内部填充颜色。

该算法的基本思想是对多边形的每条边进行填充,最终得到多边形的填充区域。

具体步骤如下:1.遍历多边形的每条边,保存每条边的起点和终点。

2.对于每个边,根据设计要求进行颜色填充。

3.对于多边形内部的区域,根据边界的颜色填充。

边界填充算法的优点是适用于复杂形状的多边形,无需处理边界相交的问题。

然而,该算法的实现相对复杂,需要处理边界的细化以及边缘像素重复填充的问题。

适用场景不同的多边形填充算法在不同场景下有不同的适用性。

计算机图形学 多边形填充

计算机图形学  多边形填充
x|ymin ymax 1/k next
y=12
边表结点
边表
P0P1 7 1 12 12 P1P2 -1 2/5 ^ 7 9 P 0P 6 5
2.桶表与 边表示例
示例多边形
y=11 y=10 y=9 y=8 y=7 y=6 y=5 y=4 y=3 y=2 y=1 3 7 P2P3 -1/3 P4P5 8 5 -1/2
4.3.2 填充过程
假定边的顺序为E0、E1、E2、E3、E4、E5和E6。这里, 边的顺序并不影响填充结果,只是方便编写循环结构而已。 填充过程如图所示。
P1(x1,y1) E1 E0 E6
P0(x0,y0)
E2 E3 E4
E5
边缘填充算法定义示例多边形
边缘填充算法原理
void CTestView::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);//计算1/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; }

《计算机图形学教学资料》第6讲-多边形填充

《计算机图形学教学资料》第6讲-多边形填充

05
多边形填充的未来发展
新型填充算法的研究
基于物理的填充算法
模拟真实世界的物理现象,如流体动 力学、表面张力等,以实现更加自然 的多边形填充效果。
智能优化算法
利用遗传算法、模拟退火等智能优化 技术,自动寻找最优的填充方案,提 高填充效率和准确性。
人工智能在多边形填充中的应用
学习型填充算法
通过机器学习技术,让算法自动学习优秀的人类设计师的填充风格,实现更加 艺术化的多边形填充效果。
优化内存管理
合理分配和释放内存,避免频繁的内 存分配和释放操作,可以提高多边形 填充的性能。
04
多边形填充的实践案例
使用OpenGL实现多边形填充
总结词
使用OpenGL进行多边形填充是一种常见的图形编程实践,它涉及到顶点数据、着色器程序和渲染流程的配置。
详细描述
首先,你需要定义多边形的顶点坐标,并将其存储在一个顶点数组中。然后,你需要编写一个OpenGL着色器程 序,用于处理顶点数据并进行渲染。在渲染过程中,你需要设置正确的顶点属性、着色器程序和渲染流程,以确 保多边形能够正确填充颜色。
填充区域
填充区域指的是多边形的内部区域,即所有被填充 的像素组成的区域。
填充颜色
填充颜色是指用于填充多边形内部的颜色,可以根 据需要选择不同的颜色。
填充算法的分类
扫描线填充算法
扫描线填充算法是一种基于扫 描线的填充算法,通过从左到 右、从上到下扫描多边形的内 部像素,对落在多边形内部的 扫描线进行上色。
在游戏开发中应用多边形填充
总结词
在游戏开发中应用多边形填充技术可以创建 更加逼真的游戏场景和角色模型。
详细描述
游戏开发者通常使用游戏引擎(如Unity或 Unreal Engine)来创建游戏场景和角色模 型。在这些引擎中,多边形填充技术被广泛 应用,以实现更加逼真的场景和角色模型。 通过合理配置顶点数据、着色器程序和渲染 流程,游戏开发者可以创建出令人惊叹的游 戏视觉效果。

MFC多边形填充

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。

多边形扫描线填充算法的概念和步骤

多边形扫描线填充算法的概念和步骤

多边形扫描线填充算法的概念和步骤嘿,咱今儿个就来聊聊多边形扫描线填充算法。

你知道不,这就像是给多边形这个大拼图上色一样有趣呢!多边形啊,它可不是个乖乖待着的主儿,有好多边和角呢。

那这扫描线填充算法呢,就是来搞定怎么把这些多边形填满颜色的。

想象一下,有一条线就像个小刷子似的,从这头刷到那头,把多边形的每一块都照顾到。

这就是扫描线啦。

它一格一格地走,每到一个地方,就看看和多边形有啥关系。

那具体步骤呢,咱可得好好说说。

首先得确定这个多边形的边啊,知道它们在哪儿,长啥样。

然后呢,这条扫描线就开始工作啦,它会和多边形的边相交,这就像它们在打招呼呢。

接着,就根据这些交点来算出要填充的区域。

这就好比是知道了要给哪块地播种一样。

然后啊,就开开心心地把颜色填上。

你说这神奇不神奇?就这么一步一步的,一个多边形就被漂亮地填满啦。

这可不比画画简单哦,这里面可有大学问呢。

比如说吧,要是交点算错了,那颜色可就填错地方啦,那就成大花脸啦!所以每一步都得仔细着点呢。

而且啊,这算法就像个小魔法师,能让那些奇奇怪怪形状的多边形都变得漂漂亮亮的。

它能让我们在屏幕上看到各种好看的图形,这可都是它的功劳呀。

你再想想,要是没有这个算法,那我们看到的图形不就干巴巴的,一点都不生动啦。

多边形扫描线填充算法,虽然名字听起来有点拗口,但它真的超级重要呢。

它就像一个默默工作的小工匠,为我们打造出美丽的图形世界。

怎么样,现在对这个多边形扫描线填充算法是不是有点感觉啦?它可不简单哦,是计算机图形学里的一个宝贝呢!以后再看到那些好看的图形,可别忘了背后有它的功劳哟!。

任意多边形区域的快速填充算法

任意多边形区域的快速填充算法

任意多边形区域的快速填充算法一、前言任意多边形区域的快速填充算法是计算机图形学中的一个重要问题,其应用广泛,例如在计算机游戏、数字地图等领域中都有广泛的应用。

本文将介绍几种常见的任意多边形区域的快速填充算法,包括扫描线算法、边界填充算法、种子填充算法等。

二、扫描线算法扫描线算法是一种基于扫描线原理的填充算法,其基本思想是将区域划分为若干个水平方向上的扫描线,然后在每条扫描线上找到交点,并根据交点进行填充。

具体步骤如下:1. 将多边形顶点按照纵坐标从小到大排序;2. 从最小纵坐标开始,依次向上扫描每条水平方向上的线段;3. 对于每条水平方向上的线段,找到与之相交的多边形边界,并记录下所有交点;4. 根据相邻两个交点之间是否为奇数个来确定是否需要进行填充。

三、边界填充算法边界填充算法也是一种常见的任意多边形区域的快速填充算法,其基本思想是通过递归调用来进行填充。

具体步骤如下:1. 对于每个多边形边界上的像素点,将其标记为“边界点”;2. 从任意一个未填充的内部像素点开始,向四周搜索,如果遇到“边界点”则停止搜索,并将搜索路径上的所有像素点标记为已填充;3. 重复步骤2直到所有内部像素点都被填充。

四、种子填充算法种子填充算法也是一种常见的任意多边形区域的快速填充算法,其基本思想是通过找到一个内部像素点作为“种子”,然后向四周扩散进行填充。

具体步骤如下:1. 随机选择一个内部像素点作为“种子”,并将其标记为已填充;2. 向四周搜索,如果遇到未被标记为已填充的像素,则将其标记为已填充,并加入到待处理列表中;3. 重复步骤2直到待处理列表为空。

五、总结以上介绍了几种常见的任意多边形区域的快速填充算法,每种算法都有其特定的优缺点,选择合适的算法需要根据具体的应用场景进行考虑。

在实际应用中,还需要考虑算法的效率、稳定性、可扩展性等方面的问题。

MFC绘图总结(5):设置绘图属性求索阁

MFC绘图总结(5):设置绘图属性求索阁

MFC绘图总结(5):设置绘图属性求索阁除了映射模式外,还有许多绘图属性可以设置,如背景、绘图方式、多边形填充方式、画弧方向、刷原点等。

1.背景1)背景色当背景模式为不透明时,背景色决定线状图的空隙颜色(如虚线中的空隙、条纹刷的空隙和文字的空隙),可以使用CDC类的成员函数GetBkColor和SetBkColor来获得和设置当前的背景颜色:COLORREF GetBkColor( ) const; // 返回当前的背景色virtual COLORREF SetBkColor( COLORREF crColor ); // 返回先前的背景色// 若出错返回0x800000002)背景模式背景模式影响有空隙的线状图的空隙(如虚线中的空隙、条纹刷的空隙和文字的空隙)用什么办法填充。

可以使用CDC类的成员函数GetBkMode和SetBkMode来获得和设置当前的背景模式:int GetBkMode( ) const; // 返回当前背景模式int SetBkMode( int nBkMode ); // 返回先前背景模式背景模式的取值2. 绘图模式绘图模式(drawing mode)指前景色的混合方式,它决定新画图的笔和刷的颜色(pbCol)如何与原有图的颜色(scCol)相结合而得到结果像素色(pixel)。

1)设置绘图模式可使用CDC类的成员函数SetROP2 (ROP = Raster OPeration 光栅操作)来设置绘图模式:int SetROP2( int nDrawMode );其中,nDrawMode可取值:绘图模式nDrawMode的取值其中,R2_COPYPEN(覆盖)为缺省绘图模式,R2_XORPEN (异或)较常用。

2)画移动图形为了能画移动的位置标识(如十字、一字)和随鼠标移动画动态图形(如直线、矩形、椭圆),必须在不破坏原有背景图形的基础上移动这些图形。

移动图形采用的是异或画图方法,移动图形的过程为:异或画图、在原位置再异或化图(擦除)、在新位置异或画图、……。

多边形填充实验

多边形填充实验

多边形填充实验实验目标: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;}}。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

实验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。

相关文档
最新文档