二维区域扫描线填充算法的实现

时间:2022-07-13 17:11:04

                                                           二维区域扫描线填充算法的实现
  这个程序从一放暑假就开始做,直做到今天,花了1个星期的时间,真是不应该啊,唉,谁让咱编程技术不太好呢,得,闲话少说。
  关于区域填充,我们常用的算法有扫描线填充算法以及种子填充算法,我现在只完成了前一种,后一种等过两天实现之,扫描算法的理解不难,可是实现起来有许多细节问题还是有点烦琐,下面这个是非常粗糙的一个版本,只能说是实现了所需,代码一点也不好,到处充斥着各种命名模糊的变量,又不很多注释,谁要是想看,那肯定费很大劲,不过整体结构是正确的。我本来想把整个算法详细地一步一步列出来,可是要讲解算法的话,还要画很多图,还要贴上来,就此做罢,如果谁也在做这个程序,就在下面留下评论即可,我一定在最短时间内给你回复。下面是我的代码,直接CTRL+V到VC6中就可以看到效果了:
  (通过这个程序我还发现,当代码一上500行,变量就开始混淆了,尤其是用来控制循环的那些小变量,还有就是在这个程序中我初步使用了VC6的调试功能 ,确实非常方便,但还有些功能不清楚,唉,慢慢来吧)

下面是一个简单的填充效果:

二维区域扫描线填充算法的实现

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#include<windows.h>  
#include<math.h>

#define FILLING    1
#define RESET      2

typedef struct        
{
 int xStart,yStart;      
 int xEnd,yEnd;         
}LINE,*PLINE;

LINE lines[100];
LINE line;
static int  j=0;
POINT draw_refresh[1000];
static int  l=0;


LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE prevInstance,PSTR szCmdLine,int iCmdShow)
{
 static TCHAR szAppName[]="2D Region Filling"; 
 HWND hwnd;          
 MSG  msg;          
 WNDCLASS wndclass;
 
 for(int i=0;i<100;i++)
 {
  lines[i].xStart=0;
  lines[i].yStart=0;
  lines[i].xEnd=0;
  lines[i].yEnd=0;
 }

 wndclass.style=CS_HREDRAW | CS_VREDRAW |CS_DBLCLKS;   
 wndclass.lpfnWndProc=WndProc;     
 wndclass.cbClsExtra=0;       
 wndclass.cbWndExtra=0;       
 wndclass.hInstance=hInstance;     
 wndclass.hIcon=LoadIcon(NULL,IDI_APPLICATION); 
 wndclass.hCursor=LoadCursor(NULL,IDC_CROSS); 
 wndclass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
 wndclass.lpszMenuName=NULL;      
 wndclass.lpszClassName=szAppName;    

 if(!RegisterClass(&wndclass))
 {
  MessageBox(NULL,"Regist window class failed!","Error",MB_OK);
 }
 hwnd=CreateWindow(szAppName,"2D Region Filling",WS_OVERLAPPED | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,hInstance,NULL);
 ShowWindow(hwnd,iCmdShow);      
 UpdateWindow(hwnd);        

 while(GetMessage(&msg,NULL,0,0))    
 {
  TranslateMessage(&msg);      
  DispatchMessage(&msg);      
 }
 return msg.wParam;        
}


LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{    
 HWND hButtonFilling;
 HWND hButtonReset;

 int cxChar=0;
 int cyChar=0;

 static PLINE head=lines;
 
 int i=0;
        
 HDC hdc;         
 PAINTSTRUCT ps; 
 RECT clientrect;

 POINT need_draw={0,0};
 POINT draw[100];
 int b=0;
 static int filled=0;

 for(int e=0;e<100;e++)
 {
  draw[e].x=0;
  draw[e].y=0;
 }

 int k=0;
 int smallest_y=0;
 int lardgest_y=0;

 int m=0;
 int n=0;
 int h=0;

 int x=0;

 int x1=0;
 int x2=0;
 int y1=0;
 int y2=0;


 int a=0;
 int c=0;

 int flag=0;

 switch(message)         
 {
 case WM_CREATE:
  cxChar=LOWORD(GetDialogBaseUnits());
  cyChar=HIWORD(GetDialogBaseUnits());
  hButtonFilling=CreateWindow(TEXT("BUTTON"),"Filling",   WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON,40*cxChar,28*cyChar,20*cxChar,7*cyChar/4,hwnd,(HMENU)FILLING,   ((LPCREATESTRUCT)lParam)->hInstance,NULL);
  hButtonReset   =CreateWindow(TEXT("BUTTON"),"Reset",     WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON,70*cxChar,28*cyChar,20*cxChar,7*cyChar/4,hwnd,(HMENU)RESET,     ((LPCREATESTRUCT)lParam)->hInstance,NULL);
  return 0;
 case WM_LBUTTONDOWN:
//  SetCapture(hwnd);
  line.xStart=(int)LOWORD(lParam);
  line.yStart=(int)HIWORD(lParam);
  for(i=0;j>=1 && i<=j-1;i++)
  {   
   if((line.xStart>lines[i].xStart-30) && (line.xStart<lines[i].xStart+30) && (line.yStart>lines[i].yStart-30) && (line.yStart<lines[i].yStart+30))
   {
    line.xStart=lines[i].xStart;
    line.yStart=lines[i].yStart;
   }
   else if((line.xStart>lines[i].xEnd-30) && (line.xStart<lines[i].xEnd+30) &&(line.yStart>lines[i].yEnd-30) && (line.yStart<lines[i].yEnd+30))
   {
    line.xStart=lines[i].xEnd;
    line.yStart=lines[i].yEnd;
   }
  }
  return 0;
 case WM_MOUSEMOVE:
  if(wParam & MK_LBUTTON)
  {
   hdc=GetDC(hwnd);
   SelectObject(hdc,GetStockObject(WHITE_PEN));
   if(line.xEnd!=0 && line.yEnd!=0)
   {
    MoveToEx(hdc,line.xStart,line.yStart,NULL);
    LineTo(hdc,line.xEnd,line.yEnd);
   }
   
   line.xEnd=(int)LOWORD(lParam);
   line.yEnd=(int)HIWORD(lParam);

   SelectObject(hdc,GetStockObject(BLACK_PEN));

   MoveToEx(hdc,line.xStart,line.yStart,NULL);
   LineTo(hdc,line.xEnd,line.yEnd);
   InvalidateRect(hwnd,NULL,FALSE);
   ReleaseDC(hwnd,hdc);
  }
  return 0;
 case WM_LBUTTONUP:
  line.xEnd=LOWORD(lParam);
  line.yEnd=HIWORD(lParam);
  for(i=0;j>=1 && i<=j-1;i++)
  {   
   if((line.xEnd>lines[i].xStart-30) && (line.xEnd<lines[i].xStart+30) && (line.yEnd>lines[i].yStart-30) && (line.yEnd<lines[i].yStart+30))
   {
    hdc=GetDC(hwnd);

    SelectObject(hdc,GetStockObject(WHITE_PEN));//clear the last black line if find a adjacent vetex
    MoveToEx(hdc,line.xStart,line.yStart,NULL);
    LineTo(hdc,line.xEnd,line.yEnd);
    

    line.xEnd=lines[i].xStart;
    line.yEnd=lines[i].yStart;

    SelectObject(hdc,GetStockObject(BLACK_PEN));

    MoveToEx(hdc,line.xStart,line.yStart,NULL);
    LineTo(hdc,line.xEnd,line.yEnd);
    
    ReleaseDC(hwnd,hdc);
   }
   else if((line.xEnd>lines[i].xEnd-30) && (line.xEnd<lines[i].xEnd+30) &&(line.yEnd>lines[i].yEnd-30) && (line.yEnd<lines[i].yEnd+30))
   {
    hdc=GetDC(hwnd);

    SelectObject(hdc,GetStockObject(WHITE_PEN));//clear the last black line if find a adjacent vetex
    MoveToEx(hdc,line.xStart,line.yStart,NULL);
    LineTo(hdc,line.xEnd,line.yEnd);

    line.xEnd=lines[i].xEnd;
    line.yEnd=lines[i].yEnd;

    SelectObject(hdc,GetStockObject(BLACK_PEN));

    MoveToEx(hdc,line.xStart,line.yStart,NULL);
    LineTo(hdc,line.xEnd,line.yEnd);
    
    ReleaseDC(hwnd,hdc);


   }
  }
  lines[j].xStart=line.xStart;
  lines[j].yStart=line.yStart;
  lines[j].xEnd=line.xEnd;
  lines[j].yEnd=line.yEnd;
  j++;
  line.xStart=0;
  line.yStart=0;
  line.xEnd=0;
  line.yEnd=0;
//  ReleaseCapture();
  return 0;
 case WM_COMMAND:
  switch(LOWORD(wParam))
  {
  case FILLING:
   smallest_y=lines[0].yStart;
   lardgest_y=lines[0].yStart;

   for(h=0;h<=100;h++)
   {
    draw[h].x=0;
    draw[h].y=0;
   }

   filled=1;

   for(h=0;h<j;h++)//find the smallest y coordinate of the edges
   {
    if(lines[h].yStart<smallest_y)
    {
     smallest_y=lines[h].yStart;
    }
    if(lines[h].yEnd<smallest_y)
    {
     smallest_y=lines[h].yEnd;
    }
   }
   for(h=0;h<j;h++)//find the lardgest y coordinate of the edges
   {
    if(lines[h].yStart>lardgest_y)
    {
     lardgest_y=lines[h].yStart;
    }
    if(lines[h].yEnd>lardgest_y)
    {
     lardgest_y=lines[h].yEnd;
    }
   }
   for(k=smallest_y;k<=lardgest_y;k++)
   {//check every scan line to filling the region
    for(m=0;m<j;m++)
    {
     a=lines[m].yStart>lines[m].yEnd ? lines[m].yStart:lines[m].yEnd ;
     c=lines[m].yStart<lines[m].yEnd ? lines[m].yStart:lines[m].yEnd ;
   
     if(k>a)
     {
      continue;      
     }
     else if(k<c)
     {
      continue;      
     }
     else if(lines[m].yStart==lines[m].yEnd && k==lines[m].yStart)
     {
      continue;
     }
     else
     {
      x=0;
      if(lines[m].yStart==k)
      {
       for(n=0;n<j;n++)
       {
        if((n!=m) && (lines[m].yStart==lines[n].yStart))
        {
         if((lines[m].yEnd>lines[m].yStart && lines[n].yEnd>lines[m].yStart) || (lines[m].yEnd<lines[m].yStart && lines[n].yEnd<lines[m].yStart))
         {
          x=lines[m].xStart;
          draw[b].x=x;
          draw[b].y=k;
          b++;
          draw[b].x=x;
          draw[b].y=k;
          b++;
         }
         else
         {
//          MessageBox(hwnd,"error2","error2",MB_OK);
          x=lines[m].xStart;

          flag=0;
          for(h=0;h<b;h++)
          {
           if(x==draw[h].x && k==draw[h].y)
           {
            flag=1;
            break;
           }
          }
          if(flag!=1)
          {
           draw[b].x=x;
           draw[b].y=k;
           b++;
          }
         }

        }
        else if((n!=m) && (lines[m].yStart==lines[n].yEnd))
        {
         if((lines[m].yEnd>lines[m].yStart && lines[n].yStart>lines[m].yStart) || (lines[m].yEnd<lines[m].yStart && lines[n].yStart<lines[m].yStart))
         {
//          MessageBox(hwnd,"error3","error3",MB_OK);
          x=lines[m].xStart;
          draw[b].x=x;
          draw[b].y=k;
          b++;
          draw[b].x=x;
          draw[b].y=k;
          b++;
         }
         else
         {
//          MessageBox(hwnd,"error4","error4",MB_OK);
          x=lines[m].xStart;

          flag=0;
          for(h=0;h<b;h++)
          {
           if(x==draw[h].x && k==draw[h].y)
           {
            flag=1;
            break;
           }
          }
          if(flag!=1)
          {
           draw[b].x=x;
           draw[b].y=k;
           b++;
          }

         }
        }
       }
      }
      else if(lines[m].yEnd==k)
      {
       for(n=0;n<j;n++)
       {
        if(m!=n && k==lines[n].yStart )
        {
         if((lines[m].yStart>lines[m].yEnd && lines[n].yEnd>lines[m].yEnd) || (lines[m].yStart<lines[m].yEnd && lines[n].yEnd<lines[m].yEnd))
         {
//          MessageBox(hwnd,"error","error",MB_OK);
          x=lines[m].xEnd;
          draw[b].x=x;
          draw[b].y=k;
          b++;
          draw[b].x=x;
          draw[b].y=k;
          b++;
         }
         else
         {
          x=lines[m].xEnd;

          flag=0;
          for(h=0;h<b;h++)
          {
           if(x==draw[h].x && k==draw[h].y)
           {
            flag=1;
            break;
           }
          }
          if(flag!=1)
          {
           draw[b].x=x;
           draw[b].y=k;
           b++;
          }
         
         }

        }
        else if(m!=n && k==lines[n].yEnd)
        {
         if((lines[m].yStart>lines[m].yEnd && lines[n].yStart>lines[m].yEnd) || (lines[m].yStart<lines[m].yEnd && lines[n].yStart<lines[m].yEnd))
         {
          x=lines[m].xEnd;
          draw[b].x=x;
          draw[b].y=k;
          b++;
          draw[b].x=x;
          draw[b].y=k;
          b++;
         }
         else
         {
          x=lines[m].xEnd;

          flag=0;
          for(h=0;h<b;h++)
          {
           if(x==draw[h].x && k==draw[h].y)
           {
            flag=1;
            break;
           }
          }
          if(flag!=1)
          {
           draw[b].x=x;
           draw[b].y=k;
           b++;
          }

         }
        }
       }
      }
      else
      {
       if(lines[m].yStart>lines[m].yEnd)
       {
        x1=lines[m].xEnd;
        y1=lines[m].yEnd;
        x2=lines[m].xStart;
        y2=lines[m].yStart;
       }
       else if(lines[m].yStart<lines[m].yEnd)
       {
        x1=lines[m].xStart;
        y1=lines[m].yStart;
        x2=lines[m].xEnd;
        y2=lines[m].yEnd;
       }
       x=x2+(x1-x2)*(y2-k)/(y2-y1);
       draw[b].x=x;
       draw[b].y=k;
       b++;
      }
     }
    }
    //check complete,then draw them
    //sorting first!
    for(h=0;h<b;h++)
    {
     for(m=h+1;m<b;m++)
     {
      if(draw[h].x>draw[m].x)
      {
       x=draw[h].x;
       draw[h].x=draw[m].x;
       draw[m].x=x;
       x=draw[h].y;
       draw[h].y=draw[m].y;
       draw[m].y=x;
      }
     }
    }
    
    hdc=GetDC(hwnd);              //real filling
    for(h=0;h<b;h+=2)
    {     
     MoveToEx(hdc,draw[h].x,draw[h].y,NULL);
     LineTo(hdc,draw[h+1].x,draw[h+1].y);
    }
    ReleaseDC(hwnd,hdc);

    for(h=0;h<b;h++)
    {
     draw_refresh[l].x=draw[h].x;
     draw_refresh[l].y=draw[h].y;
     l++;
    }

    b=0;
   }
   break;
  case RESET:
   filled=0;
   j=0;
   head=lines;
   for(int i=0;i<100;i++)
   {
    lines[i].xStart=0;
    lines[i].yStart=0;
    lines[i].xEnd=0;
    lines[i].yEnd=0;
   }
   for(h=0;h<l;h++)
   {
    draw_refresh[h].x=0;
    draw_refresh[h].y=0;
   }
   hdc=GetDC(hwnd);
   GetClientRect(hwnd,&clientrect);
   Rectangle(hdc,clientrect.left-5,clientrect.top-5,clientrect.right+5,clientrect.bottom+5);
   ReleaseDC(hwnd,hdc);

   InvalidateRect(hwnd,NULL,FALSE);
   break;
  }
  return 0;
 case WM_PAINT:
  hdc=BeginPaint(hwnd,&ps);

  for(head=lines;head->xStart!=0 && head->yStart!=0 && head->xEnd!=0 && head->yEnd!=0;head++)
  {
   MoveToEx(hdc,head->xStart,head->yStart,NULL);
   LineTo(hdc,head->xEnd,head->yEnd);
  }
  head=lines;

  if(filled==1)
  {
//   MessageBox(hwnd,"filled","filled",MB_OK);
   for(h=0;h<l;h+=2)
   {     
    MoveToEx(hdc,draw_refresh[h].x,draw_refresh[h].y,NULL);
    LineTo(hdc,draw_refresh[h+1].x,draw_refresh[h+1].y);
   }
  }

  EndPaint(hwnd,&ps);
  return 0;
 case WM_DESTROY:
  PostQuitMessage(0);
  return 0;
 }
 return DefWindowProc(hwnd,message,wParam,lParam);
}
///////////////////////////////END/////////////////////////////////////////////////
如果你真要运行下的话,请务必在粘进VC的时候把行隔开,因为我暂时还不知道怎么能以好的格式把代码贴进CSDN的BLOG中。我自己做的测试中尚未发现错误,如果你发现了,麻烦好心和你告诉我,谢谢你