矢量
矢量的加减
矢量叉积
折线段的拐向判断
判断点是否在线段上
判断两线段是否相交
1)快速排斥试验
2)跨立试验
若 P1P2 跨立 Q1Q2,则 P1,P2 分别在 Q1Q2 所在直线的两端,则有 (P1 - Q1)*(Q2 - Q1)*(Q2 - Q1)*(P2 - Q1) > 0,当 (P1 - Q1)*(Q2 - Q1) = 0 时,说明 (P1 - Q1) 与 (Q2 - Q1) 共线,但由于已经经过快速排斥试验,所以 Q1 必为 P1P2 与 Q1Q2 的交点,依然满足线段相交的条件,则跨立试验可改为:
当 (P1 - Q1)*(Q2 - Q1)*(Q2 - Q1)*(P2 - Q1) >= 0,则 P1P2 跨立 Q1Q2,当 Q1Q2 也跨立 P1P2 的时候,则 P1P2 相交
(注意式子中的 * 代表两个叉积的值的相乘,而另外的两个 * 则代表计算矢量叉积)
代码如下:
/*
向量叉乘的性质(乘积的正负性可以表示两个向量之间的相对转动方向,如a×b为正,则b通过顺时针旋转可以与a共线,
否则通过逆时针旋转可以与a共线)就可以很方便的解决这个问题。
快速排斥实验:包含两条线段的最小矩形是否相交,不相交则肯定不行,这样可省掉一些计算。
跨立试验:如果两线段相交,则两线段必然相互跨立对方。若a1b1跨立a2b2,矢量(a1-a2)和(b1-a2)位于矢量(a2-b2) 的两侧,
即 (a1-a2)×(a1-b1)*(a1-b1)×(a1-b2)>=0
同理,a2b2跨立a1b1
(a2-a1)×(a2-b2)*(a2-b2)×(a2-b1)>=0
*/
typedef struct SDL_Point{
Sint16 x;
Sint16 y;
} SDL_Point;
int max(int x, int y)
{ //比较两个数的大小,返回大的数
return x>y?x:y;
}
int min(int x, int y)
{ //比较两个数的大小,返回小的数
return x<y?x:y;
}
int multi(SDL_Point p1, SDL_Point p2, SDL_Point p0)
{ //求矢量[p0, p1], [p0, p2]的叉积
return (p1.x - p0.x) * (p2.y - p0.y) - (p2.x - p0.x) * (p1.y - p0.y);
//p0是顶点
//若结果等于0,则这三点共线
//若结果大于0,则p0p2在p0p1的逆时针方向
//若结果小于0,则p0p2在p0p1的顺时针方向
}
bool isIntersected(SDL_Point s1, SDL_Point e1, SDL_Point s2, SDL_Point e2)
{ //判断线段是否相交
//1.快速排斥试验判断以两条线段为对角线的两个矩形是否相交
//2.跨立试验
if( (max(s1.x, e1.x) > min(s2.x, e2.x)) &&
(max(s2.x, e2.x) > min(s1.x, e1.x)) &&
(max(s1.y, e1.y) > min(s2.y, e2.y)) &&
(max(s2.y, e2.y) > min(s1.y, e1.y)) &&
(multi(s2, e1, s1) * multi(e1, e2, s1) >= 0) &&
(multi(s1, e2, s2) * multi(e2, e1, s2) >= 0) )
return true;
return false;
}
判断两直线是否相交
1)斜率
2)计算两个向量的叉积
代码如下:
struct point{
int x;
int y;
};
struct v{
point start;
point end;
};
int crossProduct(v* v1, v* v2){
v vt1, vt2;
int result = 0;
vt1.start.x = 0; vt2.start.x = 0;
vt1.start.y = 0; vt2.start.y = 0;
vt1.end.x = v1->end.x - v1->start.x; vt2.end.x = v2->end.x - v2->start.x;
vt1.end.y = v1->end.y - v1->start.y; vt2.end.y = v2->end.y - v2->start.y;
result = vt1.end.x * vt2.end.y - vt2.end.x * vt1.end.y;
return result;
}