任意封闭多边形的扫描线填充算法类

    技术2022-05-19  19

    1 //扫描线填充算法类 <BR> 显示代码打印001 class CPFill  

    002 {  

    003 public:  

    004  CPoint *Point;  

    005  //指向点坐标的指针  

    006  int Count;  

    007  //多边形点的个数  

    008 public:  

    009     CPFill(int,int[],int[]);//构造函数  

    010     bool FillPolygon(CDC*);//填充多边形  

    011     bool CrossJudge(CPoint,CPoint,CPoint,CPoint,CPoint&);//判断两条线段是否相交  

    012     int GetAi(int);//获取下一个点的索引号  

    013     int GetBi(int);//获取前一个点的索引号   

    014     bool Sort(int*,int);//冒泡排序  

    015     ~CPFill();//析构函数  

    016 };  

    017 //构造函数 (模块入口,koradji 注,合理的设计这个地方,就可以完全不用改动其他的地方就可以使用这个类)     

    018 CPFill::CPFill(){ }  

    019   

    020 //获取前一个点的索引号  

    021 int CPFill::GetBi(int i)  

    022 {  

    023  return (i==0)? Count-1:i-1;  

    024 }  

    025 //获取下一个点的索引号  

    026 int CPFill::GetAi(int i)  

    027 {  

    028  return (i==Count-1)?0:i+1;  

    029 }  

    030 //在指定的pDC设备中,填充多边形  

    031 bool CPFill::FillPolygon(CDC* pDC)  

    032 {  

    033  //获取多边形中所有坐标点的最大值和最小值,作为扫描线循环的范围  

    034  int minX=Point[0].x , minY=Point[0].y;  

    035  int maxX=Point[0].x , maxY=Point[0].y;  

    036  for(int i=1;i<Count;i++)  

    037  {  

    038   if(minX>Point[i].x) minX=Point[i].x;  

    039   if(minY>Point[i].y) minY=Point[i].y;  

    040   if(maxX<Point[i].x) maxX=Point[i].x;  

    041   if(maxY<Point[i].y) maxY=Point[i].y;  

    042  }  

    043  CUIntArray xArray;  

    044  int y;  

    045  for(y=minY;y<maxY;y++)  

    046  {  

    047   //扫描线从minY开始到maxY  

    048   for(i=0;i<Count;i++)  

    049   {  

    050    //对每条边进行循环  

    051    CPoint PointCross;  

    052    int Bi=GetBi(i),Ai=GetAi(i);  

    053    //判断是否跟线段相交  

    054    if(CrossJudge(Point[Bi],Point[i],CPoint(minX,y),CPoint(maxX,y),PointCross))  

    055    {  

    056     //若是存在交点,则进行相应的判断,即判断x的坐标取两次、一次还是不取  

    057     if(PointCross==Point[i])  

    058     {  

    059      if((Point[Bi].y>PointCross.y)&&(Point[Ai].y>PointCross.y))  

    060      {     

    061       //边顶点的y值大于交点的y值,x坐标取两次  

    062       xArray.Add(PointCross.x); xArray.Add(PointCross.x);        

    063      }  

    064      else 

    065      {  

    066       //边顶点的y值在交点的y值之间,即一个顶点的y值大于交点的y值,而另一个小于,相应的x坐标取一次       

    067       if((Point[Bi].y-PointCross.y)*(Point[Ai].y-PointCross.y)<0) xArray.Add(PointCross.x);          

    068       else if(PointCross.y==Point[Ai].y) xArray.Add(PointCross.x);   

    069      }  

    070     }  

    071     else 

    072     {  

    073      if(PointCross==Point[Bi]) continue;  

    074      else xArray.Add(PointCross.x);//当交点不在线段的顶点时,x坐标只取一次  

    075     }  

    076    }   

    077   }  

    078   int *scanLineX,num=xArray.GetSize();  

    079   scanLineX=new int[num];  

    080   for(i=0;i<num;i++) scanLineX[i]=xArray.GetAt(i);//获取扫描线x值,以构成填充区间  

    081   xArray.RemoveAll();  

    082   Sort(scanLineX,num);//对scanLine(扫描线x坐标进行排序)  

    083   for(i=0;i<num;i=i+2)  

    084   {  

    085    if(i+1>=num) break;  

    086    pDC->MoveTo(scanLineX[i],y);pDC->LineTo(scanLineX[i+1],y);//填充(Koradji改进)  

    087   }  

    088         Sleep(1);//CPU暂停1ms,以体现出多边形是以扫描线的方式,一条一条的填充的  

    089   delete scanLineX;    

    090  }   

    091  return true;  

    092 }  

    093   

    094 //判断两条线段是否相交  

    095 bool CPFill::CrossJudge(CPoint L1P1,CPoint L1P2,CPoint L2P1,CPoint L2P2,CPoint& coordinate)  

    096 {  

    097  //L1P1、L1P2是一条线段的顶点坐标,而L2P1、L2P2是另一条线段的顶点坐标  

    098  if(L1P1==L1P2)  return false;//若L1P1、L1P2相等,则构不成线段,退出  

    099  if(L2P1==L2P2) return false;//若L2P1、L2P2等,则构不成线段,退出  

    100  if((L1P1.y-L1P2.y)*(L2P1.x-L2P2.x)==(L2P1.y-L2P2.y)*(L1P1.x-L1P2.x))//对斜率相等的情况下的处理  

    101  {    

    102   if((L1P1.y-L1P2.y)*(L2P1.x-L1P1.x)==(L1P1.x-L1P2.x)*(L2P1.y-L1P1.y))//判断两条线段是不是同一条线段  

    103   {     

    104    coordinate=L1P2;  

    105    return true;  

    106   }  

    107   else return false;  

    108  }  

    109  if(L1P1.x==L1P2.x)//当第一条线段斜率不存在时的  

    110  {    

    111   double x,y;  

    112   x=L1P1.x;  

    113   y=(L2P1.y-L2P2.y)*1.0/(L2P1.x-L2P2.x)*(L1P1.x-L2P1.x)+L2P1.y;  

    114   y=(float)((int)(y+0.5));  

    115   if(((L1P1.y-y)*(y-L1P2.y)>=0)&&((L1P1.x-x)*(x-L1P2.x)>=0))//判断交点是不是在该两条线段上  

    116   {     

    117    coordinate.x=L1P1.x;  

    118    coordinate.y=(int)(y+0.5);  

    119    return true;  

    120   }  

    121   return false;  

    122  }  

    123  else 

    124  {  

    125   if(L2P1.x==L2P2.x)//当第二条线段斜率不存在时  

    126   {     

    127    double x,y;  

    128    x=L2P1.x;  

    129    y=(L1P1.y-L1P2.y)*1.0/(L1P1.x-L1P2.x)*(L2P1.x-L1P1.x)+L1P1.y;  

    130    y=(float)((int)(y+0.5));  

    131    if(((L1P1.y-y)*(y-L1P2.y)>=0) && ((L1P1.x-x)*(x-L1P2.x)>=0))//判断交点是不是在该两条线段上  

    132    {      

    133     coordinate.x=L2P1.x;  

    134     coordinate.y=(int)(y+0.5);  

    135     return true;  

    136    }  

    137    return false;  

    138   }  

    139   else//两条线段斜率都存在时  

    140   {     

    141    double k1,k2;  

    142    k1=(L1P1.y-L1P2.y)*1.0/(L1P1.x-L1P2.x);  

    143    k2=(L2P1.y-L2P2.y)*1.0/(L2P1.x-L2P2.x);  

    144    //k1,k2为计算的两线段的斜率  

    145    double x,y;  

    146    x=(L2P1.y-L1P1.y-k2*L2P1.x+k1*L1P1.x)/(k1-k2);  

    147    y=(k1*k2*L2P1.x-k1*k2*L1P1.x+k2*L1P1.y-k1*L2P1.y)/(k2-k1);  

    148    x=(float)((int)(x+0.5));    

    149    y=(float)((int)(y+0.5));  

    150    if(((L1P1.y-y)*(y-L1P2.y)>=0)&&((L1P1.x-x)*(x-L1P2.x)>=0))//判断交点是不是在该两条线段上  

    151    {      

    152     coordinate.x=(int)(x+0.5);  

    153     coordinate.y=(int)(y+0.5);  

    154     return true;  

    155    }  

    156    return false;  

    157   }  

    158  }  

    159  return true;  

    160 }  

    161   

    162 //冒泡排序  

    163 bool CPFill::Sort(int* iArray,int iLength)  

    164 {   

    165  int i,j,iTemp;  

    166  bool bFlag;  

    167  for(i=0;i<iLength;i++)  

    168  {  

    169   bFlag=true;  

    170   for(j=0;j<iLength-i-1;j++)  

    171   {  

    172    if(iArray[j] > iArray[j+1])  

    173    {  

    174     iTemp=iArray[j];  

    175     iArray[j]=iArray[j+1];  

    176     iArray[j+1]=iTemp;  

    177     bFlag=false;  

    178    }  

    179   }  

    180   if(bFlag) break;  

    181  }  

    182  return true;  

    183 }  

    184 //析构函数,删除动态生成的Point指针  

    185 CPFill::~CPFill()  

    186 {  

    187  if(Point) delete [] Point;  

    188 }

    下面说说怎么为我所用这个类。  在MFC中,若多边形控制定点的变量是:CPoint *P,记录下标的变量为int  index。 则构造函数则变为

    显示代码打印1 CPFill::CPFill(int index,CPoint *P)  

    2 {  

    3  Point=new CPoint[index-1];  

    4  Count=index-1;  

    5  for(int i=0;i<Count;i++)  

    6  {  

    7      Point[i]=P[i];  

    8  }

     

    如果多边形控制定点的变量是:int px[MAX] int py[MAX],记录下标的变量为int  index。 则构造函数是:

    显示代码打印01 CPFill::CPFill(int index,int px[],int py[])  

    02 {  

    03  Point=new CPoint[index-1];  

    04  Count=index-1;  

    05  for(int i=0;i<Count;i++)  

    06  {  

    07   Point[i].x=px[i];  

    08   Point[i].y=py[i];  

    09  }  

    10 }

     

     


    最新回复(0)