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

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
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值