地區填充演算法
一.目的:
掌握有序編表法的基本原理與實現,瞭解簡單的互動技術。 二.要求:
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 defaultif (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++; //此時的值為頂點數加上1sprintf( 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 defaultCCgWP_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);elsepush(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);elsepush(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.種子線掃描法:
產生多邊形:
通過比較可知:有序編表法效率更高,種子填充演算法更靈活。