题意
给定两个三角形的三点坐标和其速度矢量,询问两三角形是否会相撞,注意题目中描述,如果点相接触也算碰撞。
题解
首先求出相对速度,即让两速度矢量相减即可。这样就可以看做一个三角形静止,另一个运动了。此时,再求出两三角形垂直于速度方向的范围是多少,如图
如果两个范围不能相交一定不会相撞。
如果相交,则取相交范围任意一点,代码中取了相交部分的中点,那么过这一点的斜率为速度矢量斜率的直线会与两个三角形都相交,如果直线与一个三角形的交点在另一三角形内部,则相撞,否则各个三角形与直线相交任取一点,这两点的矢量与速度矢量相反即可相撞。另外,需要处理相对速度为零和初始时就相撞的情况。
代码
#include <bits/stdc++.h>
typedef double lf;
struct poi {
lf x, y;
poi operator - (const poi& B) const {poi a;a.x=x-B.x,a.y=y-B.y;return a;}
lf operator * (const poi&B) const { return x*B.y-B.x*y; }
void in() { scanf("%lf%lf",&x,&y); }
void out() {
printf("%.2lf %.2lf\n",x,y);
}
}A,B,C,D,E,F,v1,v2;
typedef poi vec;
struct seg {
poi a, b;
};
int dir(poi p,seg s) {
lf tmp = (p-s.b)*(s.b-s.a);
if (tmp>0)return 1;
else if(tmp<0)return -1;
return 0;
}
bool Inter() {
int a,b,c;
a=dir(A,(seg){D,E});b=dir(A,(seg){E,F});c=dir(A,(seg){F,D});
if ((!a&&!b)||(!a&&!c)||(!b&&!c)||(!a&&b==c)||(!b&&a==c)||(!c&&a==b)||(a && a==b && b==c)) return true;
a=dir(B,(seg){D,E});b=dir(B,(seg){E,F});c=dir(B,(seg){F,D});
if ((!a&&!b)||(!a&&!c)||(!b&&!c)||(!a&&b==c)||(!b&&a==c)||(!c&&a==b)||(a && a==b && b==c)) return true;
a=dir(C,(seg){D,E});b=dir(C,(seg){E,F});c=dir(C,(seg){F,D});
if ((!a&&!b)||(!a&&!c)||(!b&&!c)||(!a&&b==c)||(!b&&a==c)||(!c&&a==b)||(a && a==b && b==c)) return true;
a=dir(D,(seg){A,B});b=dir(D,(seg){B,C});c=dir(D,(seg){C,A});
if ((!a&&!b)||(!a&&!c)||(!b&&!c)||(!a&&b==c)||(!b&&a==c)||(!c&&a==b)||(a && a==b && b==c)) return true;
a=dir(E,(seg){A,B});b=dir(E,(seg){B,C});c=dir(E,(seg){C,A});
if ((!a&&!b)||(!a&&!c)||(!b&&!c)||(!a&&b==c)||(!b&&a==c)||(!c&&a==b)||(a && a==b && b==c)) return true;
a=dir(F,(seg){A,B});b=dir(F,(seg){B,C});c=dir(F,(seg){C,A});
if ((!a&&!b)||(!a&&!c)||(!b&&!c)||(!a&&b==c)||(!b&&a==c)||(!c&&a==b)||(a && a==b && b==c)) return true;
return false;
}
lf Dot(poi a,poi b) { return a.x*b.x+a.y*b.y; }
bool GetCross(lf k,lf b,poi A,poi B,poi&ret) {
vec v = B-A;
if (v.x==0) {
lf y = k*A.x+b;
if ((y>=A.y&&y<=B.y) || (y>=B.y&&y<=A.y)) {
ret.x = A.x;ret.y = y;return true;
}
return false;
}
lf k2 = v.y/v.x;
lf b2 = A.y-k2*A.x;
if (k == k2) {
if (b == b2) { ret = A; return true; }
return false;
}
lf x = (b2-b)/(k-k2);
lf y = k*x+b;
if (x>=std::min(A.x,B.x)&&x<=std::max(A.x,B.x)&&y>=std::min(A.y,B.y)&&y<=std::max(A.y,B.y)) {
ret.x = x;ret.y = y;return true;
}
return false;
}
poi GetPoint(lf k,lf b,poi A,poi B,poi C) {
poi ans;
if (GetCross(k,b,A,B,ans)) return ans;
if (GetCross(k,b,B,C,ans)) return ans;
if (GetCross(k,b,C,A,ans)) return ans;
while(1);
}
inline void work() {
A.in(),B.in(),C.in(),v1.in();
D.in(),E.in(),F.in(),v2.in();
v2 = v2-v1;
if (Inter()) {puts("YES");return;}
if (v2.x==0&&v2.y==0) {puts("NO");return;}
if (v2.x==0) {
std::swap(v2.x,v2.y);
std::swap(A.x,A.y);
std::swap(B.x,B.y);
std::swap(C.x,C.y);
std::swap(D.x,D.y);
std::swap(E.x,E.y);
std::swap(F.x,F.y);
}
lf k = v2.y/v2.x;
lf b1,b2,b3,b1l,b1r,b2l,b2r;
b1 = A.y-k*A.x;
b2 = B.y-k*B.x;
b3 = C.y-k*C.x;
b1l=std::min(b1,std::min(b2,b3));
b1r=std::max(b1,std::max(b2,b3));
b1 = D.y-k*D.x;
b2 = E.y-k*E.x;
b3 = F.y-k*F.x;
b2l=std::min(b1,std::min(b2,b3));
b2r=std::max(b1,std::max(b2,b3));
if (b1r<b2l || b1l>b2r) { puts("NO");return; }
b1l=std::max(b1l,b2l);
b1r=std::min(b1r,b2r);
if(b1l>b1r){puts("NO");return;}
b1l=(b1l+b1r)/2.0;
poi p1=GetPoint(k,b1l,A,B,C);
poi p2=GetPoint(k,b1l,D,E,F);
p1=p2-p1;
if (Dot(p1,v2)<0) puts("YES");
else puts("NO");
}
int main() {
int T;
scanf("%d",&T);
for(int i=1;i<=T;i++)printf("Case #%d: ",i),work();
return 0;
}