【VC++开源代码栏目提醒】:以下是网学会员为您推荐的VC++开源代码-扫描线填充算法 - 图形图像,希望本篇文章对您学习有所帮助。
任意封闭多边形的扫描线填充算法类 收藏 这个
代码不是我写的,但是我肯定这
代码是一个牛人写的,放在这里供大家学习和使用啦!感谢原作者! 我在这里做了些改进: 1 去除了绘制多边形的函数,使其成为了一个纯的填充算法模块 2 改进了其成员变量,使其更容易让大多数人所使用 3 改进了填充,使其“看”(
代码上)起来更像用扫描线在填充 改进后的扫描线算法类如下: //扫描线填充算法类 class CPFill public: CPoint Point //指向点坐标的指针 int Count //多边形点的个数 public: CPFillintintint//构造函数 bool FillPolygonCDC//填充多边形 bool CrossJudgeCPointCPointCPointCPointCPointamp//判断两条线段是否相交 int GetAiint//获取下一个点的索引号 int GetBiint//获取前一个点的索引号 bool Sortintint//冒泡排序 CPFill//析构函数 //构造函数 (模块入口,koradji 注,合理的设计这个地方,就可以完全不用改动其他的地方就可以使用这个类) CPFill::CPFill //获取前一个点的索引号 int CPFill::GetBiint i return i0 Count-1:i-1 //获取下一个点的索引号 int CPFill::GetAiint i return iCount-10:i1 //在指定的pDC设备中,填充多边形 bool CPFill::FillPolygonCDC pDC //获取多边形中所有坐标点的最大值和最小值,作为扫描线循环的范围 int minXPoint0.x minYPoint0.y int maxXPoint0.x maxYPoint0.y forint i1iltCounti ifminXgtPointi.x minXPointi.x ifminYgtPointi.y minYPointi.y ifmaxXltPointi.x maxXPointi.x ifmaxYltPointi.y maxYPointi.y CUIntArray xArray int y foryminYyltmaxYy //扫描线从minY开始到maxY fori0iltCounti //对每条边进行循环 CPoint PointCross int BiGetBiiAiGetAii //判断是否跟线段相交 ifCrossJudgePointBiPointiCPointminXyCPointmaxXyPointCross //若是存在交点,则进行相应的判断,即判断x的坐标取两次、一次还是不取 ifPointCrossPointi ifPointBi.ygtPointCross.yampampPointAi.ygtPointCross.y //边顶点的y值大于交点的y值,x坐标取两次 xArray.AddPointCross.x xArray.AddPointCross.x else //边顶点的y值在交点的y值之间,即一个顶点的y值大于交点的y值,而另一个小于,相应的x坐标取一次 ifPointBi.y-PointCross.yPointAi.y-PointCross.ylt0 xArray.AddPointCross.x else ifPointCross.yPointAi.y xArray.AddPointCross.x else ifPointCrossPointBi continue else xArray.AddPointCross.x//当交点不在线段的顶点时,x坐标只取一次 int scanLineXnumxArray.GetSize scanLineXnew intnum fori0iltnumi scanLineXixArray.GetAti//获取扫描线x值,以构成填充区间 xArray.RemoveAll SortscanLineXnum//对scanLine(扫描线x坐标进行排序) fori0iltnumii2 ifi1gtnum break pDC-gtMoveToscanLineXiypDC-gtLineToscanLineXi1y//填充(Koradji改进) Sleep1//CPU暂停1ms,以体现出多边形是以扫描线的方式,一条一条的填充的 delete scanLineX return true //判断两条线段是否相交 bool CPFill::CrossJudgeCPoint L1P1CPoint L1P2CPoint L2P1CPoint L2P2CPointamp coordinate //L1P1、L1P2是一条线段的顶点坐标,而L2P1、L2P2是另一条线段的顶点坐标 ifL1P1L1P2 return false//若L1P1、L1P2相等,则构不成线段,退出 ifL2P1L2P2 return false//若L2P1、L2P2等,则构不成线段,退出 ifL1P1.y-L1P2.yL2P1.x-L2P2.xL2P1.y-L2P2.yL1P1.x-L1P2.x//对斜率相等的情况下的处理 ifL1P1.y-L1P2.yL2P1.x-L1P1.xL1P1.x-L1P2.xL2P1.y-L1P1.y//判断两条线段是不是同一条线段 coordinateL1P2 return true else return false ifL1P1.xL1P2.x//当第一条线段斜率不存在时的 double xy xL1P1.x yL2P1.y-L2P2.y1.0/L2P1.x-L2P2.xL1P1.x-L2P1.xL2P1.y yfloatinty0.5 ifL1P1.y-yy-L1P2.ygt0ampampL1P1.x-xx-L1P2.xgt0//判断交点是不是在该两条线段上 coordinate.xL1P1.x coordinate.yinty0.5 return true return false else ifL2P1.xL2P2.x//当第二条线段斜率不存在时 double xy xL2P1.x yL1P1.y-L1P2.y1.0/L1P1.x-L1P2.xL2P1.x-L1P1.xL1P1.y yfloatinty0.5 ifL1P1.y-yy-L1P2.ygt0 ampamp L1P1.x-xx-L1P2.xgt0//判断交点是不是在该两条线段上 coordinate.xL2P1.x coordinate.yinty0.5 return true return false else//两条线段斜率都存在时 double k1k2 k1L1P1.y-L1P2.y1.0/L1P1.x-L1P2.x k2L2P1.y-L2P2.y1.0/L2P1.x-L2P2.x //k1k2为计算的两线段的斜率 double xy xL2P1.y-L1P1.y-k2L2P1.xk1L1P1.x/k1-k2 yk1k2L2P1.x-k1k2L1P1.xk2L1P1.y-k1L2P1.y/k2-k1 xfloatintx0.5 yfloatinty0.5 ifL1P1.y-yy-L1P2.ygt0ampampL1P1.x-xx-L1P2.xgt0//判断交点是不是在该两条线段上 coordinate.xintx0.5 coordinate.yinty0.5 return true return false return true //冒泡排序 bool CPFill::Sortint iArrayint iLength int ijiTemp bool bFlag fori0iltiLengthi bFlagtrue forj0jltiLength-i-1j ifiArrayj gt iArrayj1 iTempiArrayj iArrayjiArrayj1 iArrayj1iTemp bFlagfalse ifbFlag break return true //析构函数删除动态生成的Point指针 CPFill::CPFill ifPoint delete Point 下面说说怎么为我所用这个类。
在MFC中,若多边形控制定点的变量是:CPoint P,记录下标的变量为int index。
则构造函数则变为 CPFill::CPFillint indexCPoint P Pointnew CPointindex-1 Countindex-1 forint i0iltCounti PointiPi 如果多边形控制定点的变量是:int pxMAX int pyMAX,记录下标的变量为int index。
则构造函数是: CPFill::CPFillint indexint pxint py Pointnew CPointindex-1 Countindex-1 forint i0iltCounti Pointi.xpxi Pointi.ypyi 这也可以算作一个例子吧!但是从这个中可以看出OO编程的优越性,事实上也为我们写程序的同志指名了方向,写模块化的程序,这个OO方法,是一致的,我想如果大家都写模块话的程序的话,不仅自己可以减少
代码数量,别人也可以方便的借鉴和使用你的
代码,如果存在一个比较不错的源码交流平台的话! 在今后的写程序的过程中,我将更加注重模块化程序的编写!今天就开始写! 本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/mekoradji/archive/2008/02/19/2106998.aspx 扫描线填充算法画多边形 计算机图形学 2006-11-03 21:11 ////////////////////////////////////////////////////////////////////////////////////////////////// // 功能: 填充多边形 // // 参数: lpPoints: 指向顶点坐标数组的指针,数组类型为POINT,多边形由它们顺次封闭连接得到 // nCount: 顶点的个数 // nColor: 填充的颜色 默认为黑色 // pDC: 设备句柄指针 // // 返回: 无返回值 // // 说明: 可以是边相交的多边形 // ////////////////////////////////////////////////////////////////////////////////////////////////// void FillPolygonLPPOINT lpPointsint nCount CDC pDC int nColor/0/ // 检查参数合法性 ASSERT_VALIDpDC ASSERTlpPoints ASSERTnCountgt2 ASSERTnColorgt0 // 边结构数据类型 typedef struct Edge int ymax // 边的最大y坐标 float x // 与当前扫描线的交点x坐标 float dx // 边所在直线斜率的倒数 struct Edge pNext // 指向下一条边 Edge LPEdge int i0j0k0 int y00y10 // 扫描线的最大和最小y坐标 LPEdge pAETNULL // 活化边表头指针 LPEdge pETNULL // 边表头指针 pAETnew Edge // 初始化表头指针,第一个元素不用 pAET-gtpNextNULL // 获取y方向扫描线边界 y0y1lpPoints0.y fori1iltnCounti iflpPointsi.ylty0 y0lpPointsi.y else iflpPointsi.ygty1 y1lpPointsi.y ify0gty1 return // 初始化边表,第一个元素不用 pETnew LPEdgey1-y01 fori0ilty1-y0i pETi new Edge pETi-gtpNextNULL fori0iltnCounti ji1nCount // 组成边的下一点 iflpPointsi.y lpPointsj.y// 如果该边不是水平的则加入边表 LPEdge peg // 指向该边的指针 LPEdge ppeg // 指向边指针的指针 // 构造边 peg new Edge klpPointsi.ygtlpPointsj.yi:j peg-gtymaxlpPointsk.y // 该边最大y坐标 kkji:j peg-gtxfloatlpPointsk.x // 该边与扫描线焦点x坐标 iflpPointsi.y lpPointsj.y peg-gtdxfloatlpPointsi.x-lpPointsj.x/lpPointsi.y-lpPointsj.y// 该边斜率的倒数 peg-gtpNextNULL // 插入边 ppegpETlpPointsk.y-y0 whileppeg-gtpNext ppegppeg-gtpNext ppeg-gtpNextpeg // end if // end for i // 扫描 foriy0ilty1i LPEdge peg0pETi-y0-gtpNext LPEdge peg1pETi-y0 ifpeg0// 有新边加入 whilepeg1-gtpNext peg1peg1-gtpNext peg1-gtpNextpAET-gtpNext pAET-gtpNextpeg0 // 按照x递增排序pAET peg0pAET whilepeg0-gtpNext LPEdge pegmaxpeg0 LPEdge peg1peg0 LPEdge pegiNULL whilepeg1-gtpNext ifpeg1-gtpNext-gtxgtpegmax-gtpNext-gtx pegmaxpeg1 peg1peg1-gtpNext pegipegmax-gtpNext pegmax-gtpNextpegi-gtpNext pegi-gtpNextpAET-gtpNext pAET-gtpNextpegi ifpeg0 pAET peg0pegi // 遍历活边表,画线 peg0pAET whilepeg0-gtpNext ifpeg0-gtpNext-gtpNext DrawLineintpeg0-gtpNext-gtxiintpeg0-gtpNext-gtpNext-gtxipDCnColor peg0peg0-gtpNext-gtpNext else break // 把ymaxi的节点从活边表删除并把每个节点的x值递增dx peg0pAET whilepeg0-gtpNext ifpeg0-gtpNext-gtymax lt i2 peg1peg0-gtpNext peg0-gtpNextpeg0-gtpNext-gtpNext //删除 delete peg1 continue peg0-gtpNext-gtxpeg0-gtpNext-gtdx //把每个节点的x值递增dx peg0peg0-gtpNext // 删除边表 fori0ilty1-y0i ifpETi delete pETi ifpAET delete pAET ifpET delete pET OpenGL作图非常方便,故日益流行,但对许多人来说,是在微机上进行的,首先碰到的问题是,如何适应微机环境。
这往往是最关键的一步,虽然也是最初级的。
一般的我不建议使用glut 包.那样难以充分发挥 windows 的界面上的功能. OpenGL 在
VC环境下的编程步骤: 建立基于OpenGL的应用程序框架 创建项目:在file -gt New中建立项目,基于单文档,View类基于Cview 添加库:在project-gtSetting中指定库 初始化:选择View-gtClass Wizard打开MFC对话框,添加相应的定义 添加类成员说明 基于OpenGL的程序框架已经构造好,以后用户只需要在对应的函数中添加程序
代码即可。
下面介绍如何在
VC 上进行 OpenGL 编程。
OpenGL 绘图的一般过程可以看作这样的先用 OpenGL 语句在 OpenGL 的绘图环境 RenderContext RC中画好图 然后再通过一个 Swap buffer 的过程把图传给操作系统的绘图环境 DeviceContext DC中实实在在地画出到屏幕上. 下面以画一条 Bezier 曲线为例,详细介绍
VC 上 OpenGL编程的方法。
文中给出了详细注释,以便给初学者明确的指引。
一步一步地按所述去做,你将顺利地画出第一个 OpenGL 平台上的图形来。
一、产生程序框架 Test.dsw New Project MFC Application Wizard EXE quotTestquot OK 注 : 加“”者指要手工敲入的字串 二、导入 Bezier 曲线类的文件 用下面方法产生 BezierCurve.h BezierCurve.cpp 两个文件: WorkSpace ClassView Test Classes lt右击弹出gt New Class Generic Class不用MFC类 quotCBezierCurvequot OK 三、编辑好 Bezier 曲线类的定义与实现 写好下面两个文件: BezierCurve.h BezierCurve.cpp 四、设置编译环境: 1. 在 BezierCurve.h 和 TestView.h 内各加上: include ltGL/gl.hgt include ltGL/glu.hgt include ltGL/glaux.hgt 2. 在集成环境中 Project Settings Link Object/library module quotopengl32.lib glu32.lib glaux.libquot OK 五、设置 OpenGL 工作环境:下面各个操作,均针对 TestView.cpp 1. 处理 PreCreateWindow: 设置 OpenGL 绘图窗口的风格 cs.style WS_CLIPSIBLINGS WS_CLIPCHILDREN CS_OWNDC 2. 处理 OnCreate:创建 OpenGL 的绘图设备。
OpenGL 绘图的机制是: 先用 OpenGL 的绘图上下文 Rendering Context 简称为 RC 把图画好,再把所绘结果通过 SwapBuffer 函数传给 Window 的 绘图上下文 Device Context 简记为 DC.要注意的是,程序运行过程中,可以有多个 DC,但只能有一个 RC。
因此当一个 DC 画完图后,要立即释放 RC,以便其它的 DC 也使用。
在后面的
代码中,将有详细注释。
int CTestView::OnCreateLPCREATESTRUCT lpCreateStruct if CView::OnCreatelpCreateStruct -1 return -1 myInitOpenGL return 0 void CTestView::myInitOpenGL m_pDC new CClientDCthis //创建 DC ASSERTm_pDC NULL if mySetupPixelFormat //设定绘图的位图格式,函数下面列出 return m_hRC wglCreateContextm_pDC-gtm_hDC//创建 RC wglMakeCurrentm_pDC-gtm_hDC m_hRC //RC 与当前 DC 相关联 //CClient m_pDC HGLRC m_hRC 是 CTestView 的成员变量 BOOL CTestView::mySetupPixelFormat //我们暂时不管格式的具体内容是什么以后熟悉了再改变格式 static PIXELFORMATDESCRIPTOR pfd sizeofPIXELFORMATDESCRIPTOR // size of this pfd 1 // version number PFD_DRAW_TO_WINDOW // support window PFD_SUPPORT_OPENGL // support OpenGL PFD_DOUBLEBUFFER // double buffered PFD_TYPE_RGBA // RGBA type 24 // 24-bit color depth 0 0 0 0 0 0 // color bits ignored 0 // no alpha buffer 0 // shift bit ignored 0 // no accumulation buffer 0 0 0 0 // accum bits ignored 32 // 32-bit z-buffer 0 // no stencil buffer 0 // no auxiliary buffer PFD_MAIN_PLANE // main layer 0 // reserved 0 0 0 // layer masks ignored int pixelformat if pixelformat ChoosePixelFormatm_pDC-gtm_hDC amppfd 0 MessageBoxquotChoosePixelFormat failedquot return FALSE if SetPixelFormatm_pDC-gtm_hDC pixelformat amppfd FALSE MessageBoxquotSetPixelFormat failedquot return FALSE return TRUE 3. 处理 OnDestroy void CTestView::OnDestroy wglMakeCurrentm_pDC-gtm_hDCNULL //释放与m_hDC 对应的 RC wglDeleteContextm_hRC //删除 RC if m_pDC delete m_pDC //删除当前 View 拥有的 DC CView::OnDestroy 4. 处理 OnEraseBkgnd BOOL CTestView::OnEraseBkgndCDC pDC // TODO: Add your message handler code here and/or call default // return CView::OnEraseBkgndpDC //把这句话注释掉,若不然,Window //会用白色北景来刷新,导致画面闪烁 return TRUE//只要空返回即可。
5. 处理 OnDraw void CTestView::OnDrawCDC pDC wglMakeCurrentm_pDC-gtm_hDCm_hRC//使 RC 与当前 DC 相关联 myDrawScene //具体的绘图函数,在 RC 中绘制 SwapBuffersm_pDC-gtm_hDC//把 RC 中所绘传到当前的 DC 上,从而 //在屏幕上显示 wglMakeCurrentm_pDC-gtm_hDCNULL//释放 RC,以便其它 DC 进行绘图 void CTestView::myDrawScene glClearColor0.0f0.0f0.0f1.0f//设置背景颜色为黑色 glClearGL_COLOR_BUFFER_BITGL_DEPTH_BUFFER_BIT glPushMatrix glTranslated0.0f0.0f-3.0f//把物体沿00-1方向平移 //以便投影时可见。
因为缺省的视点在000只有移开 //物体才能可见。
//本例是为了演示平面 Bezier 曲线的,只要作一个旋转 //变换,可更清楚的看到其 3D 效果。
//下面画一条 Bezier 曲线 bezier_curve.myPolygon//画Bezier曲线的控制多边形 bezier_curve.myDraw //CBezierCurve bezier_curve //是 CTestView 的成员变量 //具体的函数见附录 glPopMatrix glFlush //结束 RC 绘图 return 6. 处理 OnSize void CTestView::OnSizeUINT nType int cx int cy CView::OnSizenType cx cy VERIFYwglMakeCurrentm_pDC-gtm_hDCm_hRC//确认RC与当前DC关联 wcx hcy VERIFYwglMakeCurrentNULLNULL//确认DC释放RC 7 处理 OnLButtonDown void CTestView::OnLButtonDownUINT nFlags CPoint point CView::OnLButtonDownnFlags point ifbezier_curve.m_NgtMAX-1 MessageBoxquot顶点个数超过了最大数MAX50quot return //以下为坐标变换作准备 GetClientRectampm_ClientRect//获取视口区域大小 wm_ClientRect.right-m_ClientRect.left//视口宽度 w hm_ClientRect.bottom-m_ClientRect.top//视口高度 h //wh 是CTestView的成员变量 centerxm_ClientRect.leftm_ClientRect.right/2//中心位置, centerym_ClientRect.topm_ClientRect.bottom/2//取之作原点 //centerxcentery 是 CTestView 的成员变量 GLdouble tmpxtmpy tmpxscrx2glxpoint.x//屏幕上点坐标转化为OpenGL画图的规范坐标 tmpyscry2glypoint.y bezier_curve.m_Vertexbezier_curve.m_N.xtmpx//加一个顶点 bezier_curve.m_Vertexbezier_curve.m_N.ytmpy bezier_curve.m_N//顶点数加一 InvalidateRectNULLTRUE//发送刷新重绘消息 double CTestView::scrx2glxint scrx return doublescrx-centerx/doubleh double CTestView::scry2glyint scry 附录: 1.CBezierCurve 的声明: BezierCurve.h class CBezierCurve public: myPOINT2D m_VertexMAX//控制顶点,以数组存储 //myPOINT2D 是一个存二维点的结构 //成员为Gldouble xy int m_N //控制顶点的个数 public: CBezierCurve.
上一篇:
C++程序员低手箴言
下一篇:
10years匿名社交网