Sutherland-Hodgeman 多边形裁剪
Sunday, 18. September 2005, 07:17:07
Sutherland—Hodgeman 多边形裁剪的原理即是将多边形看作一个整体,按裁剪窗口的每一条边依次裁剪,因此也可称为连续多边形裁剪。贴在这里的算法参照了电子工业版《计算机图形学》(Donald Hearn 等著)中的相关算法,并在CSDN技术社区诸位朋友的帮助下完成,在此致谢。这段代码可在VC6环境下通过,欢迎各位提出意见或者改进建议。
include "malloc.h"
#define N_EDGE 4
typedef enum {Left,Right,Bottom,Top} Edge;
struct dcPt
{
int x;
int y;
};
struct wcPt2
{
int x;
int y;
};
int inside(wcPt2 p,Edge b,dcPt wMin,dcPt wMax)//判断点所在位置
{
switch(b)
{
case Left: if(p.x<wMin.x) return (false);break;
case Right: if(p.x>wMax.x) return (false);break;
case Bottom: if(p.y<wMin.y) return (false);break;
case Top: if(p.y>wMax.y) return (false);break;
}
return (true);
}
int cross(wcPt2 p1,wcPt2 p2,Edge b,dcPt wMin,dcPt wMax)//判断裁还是不裁
{
if(inside(p1,b,wMin,wMax)==inside(p2,b,wMin,wMax))
return (false);
else return (true);
}
wcPt2 intersect(wcPt2 p1,wcPt2 p2,Edge b,dcPt wMin,dcPt wMax)//计算交点
{
wcPt2 iPt;
float m;
float dx,dy;
if(p1.x!=p2.x)
{
dy=float(p1.y-p2.y);
dx=float(p1.x-p2.x);
m=dy/dx;
}
switch(b)
{
case Left:
iPt.x=wMin.x;
iPt.y=int(p2.y+(wMin.x-p2.x)*m);
break;
case Right:
iPt.x=wMax.x;
iPt.y=int(p2.y+(wMax.x-p2.x)*m);
break;
case Bottom:
iPt.y=wMin.y;
if(p1.x!=p2.x) iPt.x=int(p2.x+(wMin.y-p2.y)/m);
else iPt.x=p2.x;
break;
case Top:
iPt.y=wMax.y;
if(p1.x!=p2.x) iPt.x=int(p2.x+(wMax.y-p2.y)/m);
else iPt.x=p2.x;
break;
}
return(iPt);
}
void clipPoint(wcPt2 p,Edge b,dcPt wMin,dcPt wMax,wcPt2 *pOut,int *cnt,wcPt2 *first[],wcPt2 *s)//连续裁剪,将结果代入下一裁剪边或最终多边形
{
wcPt2 iPt;
if(! first)
first=&p;
else
if(cross(p,s,b,wMin,wMax))
{
iPt=intersect(p,s,b,wMin,wMax);
if(b<Top)
clipPoint(iPt,Edge(b+1),wMin,wMax,pOut,cnt,first,s);
else
{
pOut[*cnt]=iPt;
(*cnt)++;
}
}
s=p;
if(inside(p,b,wMin,wMax))
if(b<Top)
clipPoint(p,Edge(b+1),wMin,wMax,pOut,cnt,first,s);
else
{
pOut[*cnt]=p;
(*cnt)++;
}
}
void closeClip(dcPt wMin,dcPt wMax,wcPt2 *pOut,int *cnt,wcPt2 *first[],wcPt2 *s)//完成多边形裁剪
{
wcPt2 i;
Edge b;
for(b=Left;b<=Top;)
{
if(cross(s,*first,b,wMin,wMax))
{
i=intersect(s,*first,b,wMin,wMax);
if(b<Top)
{
clipPoint(i,Edge(b+1),wMin,wMax,pOut,cnt,first,s);
}
else
{
pOut[*cnt]=i;
(*cnt)++;
}
}
b=Edge(b+1);
}
}
int clipPolygon(dcPt wMin,dcPt wMax,int n,wcPt2 *pIn,wcPt2 *pOut)
{
wcPt2 *first[N_EDGE]={0,0,0,0},s[N_EDGE];
int i,cnt=0;
for(i=0;i<n;i++)
clipPoint(pIn,Left,wMin,wMax,pOut,&cnt,first,s);
closeClip(wMin,wMax,pOut,&cnt,first,s);
return (cnt);
}
include "malloc.h"
#define N_EDGE 4
typedef enum {Left,Right,Bottom,Top} Edge;
struct dcPt
{
int x;
int y;
};
struct wcPt2
{
int x;
int y;
};
int inside(wcPt2 p,Edge b,dcPt wMin,dcPt wMax)//判断点所在位置
{
switch(b)
{
case Left: if(p.x<wMin.x) return (false);break;
case Right: if(p.x>wMax.x) return (false);break;
case Bottom: if(p.y<wMin.y) return (false);break;
case Top: if(p.y>wMax.y) return (false);break;
}
return (true);
}
int cross(wcPt2 p1,wcPt2 p2,Edge b,dcPt wMin,dcPt wMax)//判断裁还是不裁
{
if(inside(p1,b,wMin,wMax)==inside(p2,b,wMin,wMax))
return (false);
else return (true);
}
wcPt2 intersect(wcPt2 p1,wcPt2 p2,Edge b,dcPt wMin,dcPt wMax)//计算交点
{
wcPt2 iPt;
float m;
float dx,dy;
if(p1.x!=p2.x)
{
dy=float(p1.y-p2.y);
dx=float(p1.x-p2.x);
m=dy/dx;
}
switch(b)
{
case Left:
iPt.x=wMin.x;
iPt.y=int(p2.y+(wMin.x-p2.x)*m);
break;
case Right:
iPt.x=wMax.x;
iPt.y=int(p2.y+(wMax.x-p2.x)*m);
break;
case Bottom:
iPt.y=wMin.y;
if(p1.x!=p2.x) iPt.x=int(p2.x+(wMin.y-p2.y)/m);
else iPt.x=p2.x;
break;
case Top:
iPt.y=wMax.y;
if(p1.x!=p2.x) iPt.x=int(p2.x+(wMax.y-p2.y)/m);
else iPt.x=p2.x;
break;
}
return(iPt);
}
void clipPoint(wcPt2 p,Edge b,dcPt wMin,dcPt wMax,wcPt2 *pOut,int *cnt,wcPt2 *first[],wcPt2 *s)//连续裁剪,将结果代入下一裁剪边或最终多边形
{
wcPt2 iPt;
if(! first)
first=&p;
else
if(cross(p,s,b,wMin,wMax))
{
iPt=intersect(p,s,b,wMin,wMax);
if(b<Top)
clipPoint(iPt,Edge(b+1),wMin,wMax,pOut,cnt,first,s);
else
{
pOut[*cnt]=iPt;
(*cnt)++;
}
}
s=p;
if(inside(p,b,wMin,wMax))
if(b<Top)
clipPoint(p,Edge(b+1),wMin,wMax,pOut,cnt,first,s);
else
{
pOut[*cnt]=p;
(*cnt)++;
}
}
void closeClip(dcPt wMin,dcPt wMax,wcPt2 *pOut,int *cnt,wcPt2 *first[],wcPt2 *s)//完成多边形裁剪
{
wcPt2 i;
Edge b;
for(b=Left;b<=Top;)
{
if(cross(s,*first,b,wMin,wMax))
{
i=intersect(s,*first,b,wMin,wMax);
if(b<Top)
{
clipPoint(i,Edge(b+1),wMin,wMax,pOut,cnt,first,s);
}
else
{
pOut[*cnt]=i;
(*cnt)++;
}
}
b=Edge(b+1);
}
}
int clipPolygon(dcPt wMin,dcPt wMax,int n,wcPt2 *pIn,wcPt2 *pOut)
{
wcPt2 *first[N_EDGE]={0,0,0,0},s[N_EDGE];
int i,cnt=0;
for(i=0;i<n;i++)
clipPoint(pIn,Left,wMin,wMax,pOut,&cnt,first,s);
closeClip(wMin,wMax,pOut,&cnt,first,s);
return (cnt);
}
