思路
分两种情况
1、不发生碰撞
2、发生碰撞
只要写出点A的射线方程,圆的方程,联立即可求出碰撞时间t的二次方程。
通过二次方程的 delta 与 0 的大小关系,判断是否碰撞。
1、不发生碰撞时
直接看点B是否在A的射线上
2、发生碰撞时
先看点 B 是否在A到碰撞点上(入射线),然后再看是否在出射线上,因为求出射线比较麻烦,这里是算出切线方程,算出点B关于切线的对称点,然后判断点B是否在A射线上。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const double eps = 1e-8;
int sgn(double x){
if(fabs(x) < eps)
return 0;
if(x > 0.0)
return 1;
return -1;
}
int main(){
int T, Case = 1; scanf("%d", &T);
while(T--){
double Ox, Oy, r, Ax, Ay, Vx, Vy, Bx, By;
scanf("%lf %lf %lf", &Ox, &Oy, &r);
scanf("%lf %lf %lf %lf", &Ax, &Ay, &Vx, &Vy);
scanf("%lf %lf", &Bx, &By);
printf("Case #%d: ", Case++);
double a, b, c;
a = Vx * Vx + Vy * Vy;
b = 2.0 * ( Vx * (Ax - Ox) + Vy * (Ay - Oy));
c = (Ax - Ox) * (Ax - Ox) + (Ay - Oy) * (Ay - Oy) - r * r;
double delta = b * b - 4 * a * c;
bool flag;
double t1, t2;
if(sgn(delta) <= 0){///小于等于,无碰撞,直接看射线
if(sgn(Vx) != 0){
t1 = (Bx - Ax) / Vx;
if(sgn(By - Ay - Vy * t1) == 0){
flag = true;
}else{
flag = false;
}
}
else if(sgn(Vy) != 0){
t2 = (By - Ay) / Vy;
if(sgn(Bx - Ax - Vx * t2) == 0){
flag = true;
}else{
flag = false;
}
}
}else{///大于
double t1 = (-b - sqrt(delta)) / (2.0 * a), t2;
if(t1 < 0.0){///碰撞点在A点后面,不会碰撞,只看射线。
if(sgn(Vx) != 0){
t1 = (Bx - Ax) / Vx;
if(sgn(By - Ay - Vy * t1) == 0){
flag = true;
}else{
flag = false;
}
}else if(sgn(Vy) != 0){
t2 = (By - Ay) / Vy;
if(sgn(Bx - Ax - Vx * t2) == 0){
flag = true;
}else{
flag = false;
}
}
}else{///求解碰撞点的坐标,新的向量。(由于不会求新的向量,所以直接算出碰撞点的切线,然后将B点关于切线对称,看对称点是否在碰撞点的射线上即可)
double hx = Ax + t1 * Vx, hy = Ay + t1 * Vy;///碰撞坐标
double A, B, C;///切线方程
A = hx - Ox;
B = hy - Oy;
C = Ox * (Ox - hx) + Oy * (Oy - hy) - r * r;
//double t1 = (-b - sqrt(delta)) / (2.0 * a);
///看点B是否在入射线上
if(sgn(Vx) != 0){
double t = (Bx - Ax) / Vx;
if(sgn(By - Ay - Vy * t) == 0 && sgn(t - t1) <= 0){
printf("Yes\n");
continue;
}else{
flag = false;
}
}else if(sgn(Vy) != 0){
double t = (By - Ay) / Vy;
if(sgn(Bx - Ax - Vx * t) == 0 && sgn(t - t1) <= 0){
printf("Yes\n");
continue;
}else{
flag = false;
}
}
///求点B关于切线方程的对称点
double Bxx = Bx - (2.0 * A * (A * Bx + B * By + C)) / (A * A + B * B);
double Byy = By - (2.0 * B * (A * Bx + B * By + C)) / (A * A + B * B);
Bx = Bxx, By = Byy;
Ax = hx, Ay = hy;
///看点B是否在出射线上
if(sgn(Vx) != 0){
t1 = (Bx - Ax) / Vx;
if(sgn(By - Ay - Vy * t1) == 0){
flag = true;
}else{
flag = false;
}
}
else if(sgn(Vy) != 0){
t2 = (By - Ay) / Vy;
if(sgn(Bx - Ax - Vx * t2) == 0){
flag = true;
}else{
flag = false;
}
}
}
}
printf("%s\n", flag ? "Yes" : "No");
}
return 0;
}
/*
3
0 0 1
2 2 0 1
-1 -1
0 0 1
-1 2 1 -1
1 2
0 0 1
-2 3 1 -1
-1 2
*/