之前基本上遇到的多边形切割问题都是凸多边形问题,而针对凹多边形的切割问题却很少。偶然发现一个做得特别棒的滑动切割的游戏,游戏中主要是使用多边形切割以及多边形碰撞算法。针对多边形切割的实现做了一下研究,现在把实现跟大家分享一下。
给定任意一个多边形以及一条线段,如果多边形被线段切割,计算切割后产生的多个多边形。实现的算法思想如下:
1、求多边形每一条边跟线段的交点,将交点插入多边形的顶点序列,得到新的顶点序列。
2、如果交点超过一个,多边形就有可能被切割。
3、先判断从第一个交点开始,线段是处于多边形内部还是多边形外部,找出距离交点最近的另一个交点,
- 如果另一个交点是最后一个交点并且这两个交点连线的中点在多边形外,那么当前交点之后线段开始处于多边形内
- 如果另一个交点是最后一个交点并且这两个交点连线的中点在多边内部,那么当前交点之后线段开始处于多边形外部
- 如果另一个交点当前交点的下一个交点并且这两个交点连线的中点在多边内部,那么当前交点之后线段开始处于多边形内部
- 如果另一个交点当前交点的下一个交点并且这两个交点连线的中点在多边外部,那么当前交点之后线段开始处于多边形外部
4、从第一个交点开始对新的顶点序列中的点开始拆分,如果多边形被切割了,那么当前交点一定是分割之后两个多边形的交点,在遇到下一个交点之前,原来多边形的顶点需要根据当前线段的状态来处理,如果当前线段处于多边形内部,这些点会被分割给新的多边形,如果线段在多边形外部,那么这些点还属于原多边形。
5、遇到新的交点,根据线段的状态来判断,如果线段之前是处于多边形内部,那么当前交点个前一个交点的连线将原多边形分割得到了新的多边形,并且接下来线段的状态会发生变化,线段开始处于多边形外部。如果线段之前处于多边形外部,那么从当前交点开始,线段开始处于多边形内部,当前交点和下一个交点将会分割元多边形,产生新的多边形。
算法使用typescript实现如下:
//求两条线段的交点
//返回值:[n,p] n:0相交,1在共有点,-1不相交 p:交点
public static lineCrossPoint(p1:cc.Vec2,p2:cc.Vec2,q1:cc.Vec2,q2:cc.Vec2){
let a = p1,b = p2,c = q1,d = q2;
let s1,s2,s3,s4;
let d1,d2,d3,d4;
let p:cc.Vec2 = new cc.Vec2(0,0);
d1=this.dblcmp(s1=this.ab_cross_ac(a,b,c),0);
d2=this.dblcmp(s2=this.ab_cross_ac(a,b,d),0);
d3=this.dblcmp(s3=this.ab_cross_ac(c,d,a),0);
d4=this.dblcmp(s4=this.ab_cross_ac(c,d,b),0);
//如果规范相交则求交点
if ((d1^d2)==-2 && (d3^d4)==-2)
{
p.x=(c.x*s2-d.x*s1)/(s2-s1);
p.y=(c.y*s2-d.y*s1)/(s2-s1);