区域填充算法

16 篇文章 0 订阅
7 篇文章 1 订阅

                                       区域填充算法

一.目的:

   掌握有序编表法的基本原理与实现,了解简单的交互技术。

二.要求:

    1.  边界种子交互输入;

    2.  实例包含有凹凸多边形类型;

    3.  支持颜色选择,图案编辑。

三.内容:

    1.实现有序编表法;

    求出扫描线和多边形每条边的交点(x1,y1)的横纵坐标的最大最小值Xmin,Xmax,Ymax,Ymin。利用求出的每条边交点横纵坐标的最大最小值编成一张从小到大排列的表(float m_yMax[N],m_yMin[N],m_Xa[N],m_Dx[N]),然后根据    这张表进行多边形填充。其中的一些函数功能说明:

    void CCgFQlineDemoView::pFillScan(CDC* pDC)

    void FillPolygon(int n, CPoint *points, CDC *pDC)//编表法实现

    void pLoadPolygon(int pNumbers,CPoint *points)//多边形加载

    void pInsertLine(float x1, float y1,float x2, float y2)//求交点

    void pInclude();

    void pUpdateXvalue();

    void pXsort(intBegin, int i)//建立有序表,即将各交点大小排序

   2. 实现种子填充算法:

        算法原理:

     (1)栈顶象素出栈;

     (2)沿扫描线对出栈象素的左右象素进行填充,直至遇到边界象素为止,即每出栈一个像素,就对包含该象素的整个区间进行填充;

     (3)上述区间内最左,最右的象素分别记为x1和x2;

     (4)在区间[x1,x2]中检查与当前扫描线相邻的上下两条扫描线的有关象素是否全为边界象素或已填充的象素,若存在非边界,未填充的象素,则把每一区间的最右象素取作种子象素入栈。

      该算法的实现函数为void ScanLineFill(CDC* pDC, CPoint point, int color0)

四.关键代码:

    (1)void CCgWP_FQlineDemoView::OnMouseMove(UINT nFlags,CPoint point) 
void CCgWP_FQlineDemoView::OnMouseMove(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	if (m_pNumbers) {
		
		m_pDC->SetROP2(2);
		m_pDC->MoveTo(m_pAccord[m_pNumbers-1]);
		m_pDC->LineTo(m_mousePoint);
		
		m_mousePoint = point;
		m_pDC->MoveTo(m_pAccord[m_pNumbers-1]);
		m_pDC->LineTo(m_mousePoint);
	}	
	CView::OnMouseMove(nFlags, point);
}
     (2)void CCgWP_FQlineDemoView::OnLButtonDown(UINT nFlags,CPoint point) 

void CCgWP_FQlineDemoView::OnLButtonDown(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
   CCgWP_FQlineDemoDoc* pDoc = (CCgWP_FQlineDemoDoc*) GetDocument();
	if( pDoc->SIGN){
	           
		if (m_pNumbers < N) {
		       m_pAccord[m_pNumbers] = point;
		       m_pNumbers++;
		
		       m_mousePoint = point;
		}
	}
	else{
            m_tempPoint = point;
		    if( pDoc->SEEDFillMode)
              
			CCgWP_FQlineDemoView::ScanLineFill(m_pDC, m_tempPoint,RGB(0,0,255));
	}
		
	CView::OnLButtonDown(nFlags, point);
}

   (3)void CCgWP_FQlineDemoView::OnLButtonDblClk(UINT nFlags, CPointpoint) 

void CCgWP_FQlineDemoView::OnLButtonDblClk(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
    CCgWP_FQlineDemoDoc* pDoc = (CCgWP_FQlineDemoDoc*) GetDocument();
	if(pDoc->SIGN)
	{
	m_pDC->MoveTo(m_pAccord[m_pNumbers-1]);
    m_pDC->LineTo(m_pAccord[0]);
	
	m_pAccord[m_pNumbers] = m_pAccord[0];
	m_pNumbers++; //此时的值为顶点数加上1
	sprintf( stringnumber, "%d", m_pNumbers-1 );
	m_pDC->TextOut(100,200,stringnumber);
	FillPolygon(m_pNumbers, m_pAccord, m_pDC);
	m_pNumbers = 0; // 防止鼠标拖动时划线
	CView::OnLButtonDblClk(nFlags, point);
	}
}

 (4)void CCgWP_FQlineDemoView::FillPolygon(int n, CPoint *points, CDC*pDC)

void CCgWP_FQlineDemoView::FillPolygon(int n, CPoint *points, CDC *pDC)
{

	CCgWP_FQlineDemoDoc* pDoc = (CCgWP_FQlineDemoDoc*) GetDocument();

	m_edgeNumbers = 0;
	pLoadPolygon(n, points);//加载多边形,通过记录m_yMax[N],m_yMin[N],m_Xa[N],m_Dx[N]来记录每一条边
	
	m_Begin = m_End = 0;
	m_Scan = (int)m_yMax[0];
	pInclude(); // 求交
	pUpdateXvalue();//改变m_Xa[N]的值
	while (m_Begin != m_End) {
		pFillScan(pDC);
		m_Scan--;
		pInclude();
		pUpdateXvalue();
	}//当已经求交边数和已经删除的边数不相等时,进入循环
}

 (5)void CCgWP_FQlineDemoView::pLoadPolygon(intpNumbers,CPoint *points)

void CCgWP_FQlineDemoView::pLoadPolygon(int pNumbers,CPoint *points)
{
	float x1,y1,x2,y2;
	
	x1 = points[0].x;    y1 = points[0].y+0.5;
	for (int i = 1; i < pNumbers; i++) {
        x2 = points[i].x;  y2 = points[i].y+0.5;
		if( y1-y2 )
		  pInsertLine(x1,y1,x2,y2);
		  x1 = x2; y1 = y2;
		
	}
}

  (6) void CCgWP_FQlineDemoView::pInsertLine(floatx1, float y1,float x2, float y2)

 void CCgWP_FQlineDemoView::pInsertLine(float x1, float y1,
							  float x2, float y2)
{
	int i;
	float Ymax,Ymin;
		
	
	Ymax = (y2 > y1) ? y2 :  y1;
	Ymin = (y2 < y1) ? y2 : y1;
	i = m_edgeNumbers;
	while (i > 0 && Ymax > m_yMax[i-1]) {
          m_yMax[i] = m_yMax[i-1];
	      m_yMin[i] = m_yMin[i-1];
	      m_Dx[i] = m_Dx[i-1];
		  m_Xa[i] = m_Xa[i-1];
		  i--;                                  
	}
	m_yMax[i] = Ymax;
	m_yMin[i] = Ymin;
	if (y2 > y1) m_Xa[i] = x2;
	else         m_Xa[i] = x1;
	m_Dx[i] = (x1 - x2) / (y2 - y1);
	m_edgeNumbers++;
}

   (7) void CCgWP_FQlineDemoView::pInclude()

 void CCgWP_FQlineDemoView::pInclude()
{
	
	while (m_End < m_edgeNumbers && m_yMax[m_End] > m_Scan) {
        m_Xa[m_End] = m_Xa[m_End] - 0.5 * m_Dx[m_End];
		m_End++;
	}
}

  (8) void CCgWP_FQlineDemoView::pUpdateXvalue()

void CCgWP_FQlineDemoView::pUpdateXvalue()
{
	int i,start = m_Begin;
	
	for (i = start; i < m_End; i++) {
		if (m_Scan > m_yMin[i]) {
			m_Xa[i] += m_Dx[i];
			pXsort(m_Begin, i);
		} else {
		 	for (int j = i; j > m_Begin; j--) 
			{
				m_yMin[j] = m_yMin[j-1];
				m_Xa[j] = m_Xa[j-1];
				m_Dx[j] = m_Dx[j-1];   
			}
			m_Begin++;
		}
	}
	
}

  (9) void CCgWP_FQlineDemoView::pXsort(intBegin, int i)

void CCgWP_FQlineDemoView::pXsort(int Begin, int i)
{
	float temp;
	
    while (i > Begin && m_Xa[i] < m_Xa[i-1]) {
		temp = m_Xa[i];
        m_Xa[i] = m_Xa[i-1];
		m_Xa[i-1] = temp;
		temp = m_yMin[i];
        m_yMin[i] = m_yMin[i-1];
		m_yMin[i-1] = temp;
		temp = m_Dx[i];
        m_Dx[i] = m_Dx[i-1];
		m_Dx[i-1] = temp;
		i--;
	}
}
   (10)voidCCgWP_FQlineDemoView::pFillScan(CDC* pDC)

void CCgWP_FQlineDemoView::pFillScan(CDC* pDC)
{
	int x=0,y=0;
	CCgWP_FQlineDemoDoc* pDoc = (CCgWP_FQlineDemoDoc*) GetDocument();
	
    if( pDoc->SEEDFillMode == 0 ){
	pDC->SetROP2(10);
	for (int i = m_Begin; i < m_End; i += 2) {
		if (pDoc->SOLIDFillMode) {
			pDC->MoveTo(m_Xa[i],   m_Scan);
			pDC->LineTo(m_Xa[i+1], m_Scan);
		} else {
		  y = m_Scan;
		  for (int x = m_Xa[i]; x < m_Xa[i+1]; x++) 
			if (m_patternData[y%7][x%6])
				pDC->SetPixel(x, y, RGB(0,0,255)); 

				}
		}

	}
}

  (11) void CCgWP_FQlineDemoView::OnRButtonDown(UINTnFlags, CPoint point) 

void CCgWP_FQlineDemoView::OnRButtonDown(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	CCgWP_FQlineDemoDoc* pDoc = (CCgWP_FQlineDemoDoc*) GetDocument();
	pDoc->SIGN = !pDoc->SIGN;
	CView::OnRButtonDown(nFlags, point);
}

  (12) void CCgWP_FQlineDemoView::ScanLineFill(CDC*pDC, CPoint point, int color0)

 void CCgWP_FQlineDemoView::ScanLineFill(CDC* pDC, CPoint point, int color0)
{

	CCgWP_FQlineDemoDoc* pDoc = (CCgWP_FQlineDemoDoc*) GetDocument();

    int clr,color;
	int x,y,x0,y0,xl,xr,flag,xnextspan;
	iStack=0;
	pDC->SetROP2(10);
	x=point.x;
	y=point.y;
	y0=y;
	push(x,y);
	color=pDC->SetPixel(x,y,color0);
	while(iStack >0)
	{
		pop(x,y);
		clr=pDC->SetPixel(x,y,RGB(255,0,255));
		x0=x+1;
		while(pDC->GetPixel(x0,y) !=color)
		{
			pDC->SetPixel(x0,y,RGB(255,0,255));
			x0++;
		}
		xr=x0-1;	// 最右像素
		x0=x-1;
		while(pDC->GetPixel(x0,y) !=color)
		{
			pDC->SetPixel(x0,y,RGB(255,0,255));
			x0--;
		}
		xl=x0+1;	// 最左像素
		
		x0=xl;
		y=y+1;
		while(x0<=xr)
		{
			flag=0;
			while(pDC->GetPixel(x0,y) !=color && 
				  pDC->GetPixel(x0,y) !=clr &&  x0<xr)
			{
				if(flag==0) flag=1;
				x0++;
			}
			if(flag==1)
			{
				if(x0==xr && pDC->GetPixel(x0,y) !=color && 
						pDC->GetPixel(x0,y) !=clr)
					push(x0,y);
				else
					push(x0-1,y);
				flag=0;
			}
			xnextspan=x0;
			while(pDC->GetPixel(x0,y) ==color || 
				  pDC->GetPixel(x0,y) ==clr &&  x0<=xr)
				  x0++;
			if(xnextspan==x0) x0++;
		}
		
		x0=xl;
		y=y-2;
		while(x0<=xr)
		{
			flag=0;
			while(pDC->GetPixel(x0,y) !=color && 
				  pDC->GetPixel(x0,y) !=clr &&  x0<xr)
			{
				if(flag==0) flag=1;
				x0++;
			}
			if(flag==1)
			{
				if(x0==xr && pDC->GetPixel(x0,y) !=color && 
						pDC->GetPixel(x0,y) !=clr)
					push(x0,y);
				else
					push(x0-1,y);
				flag=0;
			}
			xnextspan=x0;
			while(pDC->GetPixel(x0,y) ==color || 
				  pDC->GetPixel(x0,y) ==clr &&  x0<=xr)
				  x0++;
			if(xnextspan==x0) x0++;
		}
	}	
}

   (13)voidCCgWP_FQlineDemoView::push(int x, int y)

void CCgWP_FQlineDemoView::push(int x, int y)
{
   if(iStack>1000)
		return;
	else
	{
		iStack++;
		stackX[iStack]=x;
		stackY[iStack]=y;
	}

}

   (14)intCCgWP_FQlineDemoView::pop(int &x, int &y)

int CCgWP_FQlineDemoView::pop(int &x, int &y)
{
	if(iStack<=0) return -1;
	x=stackX[iStack];
	y=stackY[iStack];
	iStack--;
	return iStack;

}<strong>
</strong>

五.结果及分析:

   1. 有序编表法:

    
   

  

  2.种子线扫描法:

    生成多边形:

  


  


    通过比较可知:有序编表法效率更高,种子填充算法更灵活。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值